home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 51 / Amiga Format CD51 (2000-03-10)(Future Publishing)(GB)[!][issue 2000-04].iso / -in_the_mag- / workbench / term_4.8 / extras / source / term-source.lha / Tools.c < prev    next >
C/C++ Source or Header  |  1997-10-03  |  72KB  |  3,948 lines

  1. /*
  2. **    Tools.c
  3. **
  4. **    Miscellaneous support routines
  5. **
  6. **    Copyright © 1990-1997 by Olaf `Olsen' Barthel
  7. **        All Rights Reserved
  8. **
  9. **    :ts=4
  10. */
  11.  
  12. #ifndef _GLOBAL_H
  13. #include "Global.h"
  14. #endif
  15.  
  16.     /* ListViewStateFill(struct LVDrawMsg *Msg):
  17.      *
  18.      *    Draw the ghosting pattern over a ghosted listview line.
  19.      */
  20.  
  21. VOID
  22. ListViewStateFill(struct LVDrawMsg *Msg)
  23. {
  24.     if(Msg->lvdm_State == LVR_SELECTEDDISABLED || Msg->lvdm_State == LVR_NORMALDISABLED)
  25.     {
  26.         struct RastPort    *RPort = Msg->lvdm_RastPort;
  27.         ULONG Ghosting = 0x44441111;
  28.  
  29.         SetABPenDrMd(RPort,Msg->lvdm_DrawInfo->dri_Pens[SHADOWPEN],0,JAM1);
  30.  
  31.         SetAfPt(RPort,(UWORD *)&Ghosting,1);
  32.  
  33.         RectFill(RPort,Msg->lvdm_Bounds.MinX,Msg->lvdm_Bounds.MinY,Msg->lvdm_Bounds.MaxX,Msg->lvdm_Bounds.MaxY);
  34.  
  35.         SetAfPt(RPort,NULL,0);
  36.     }
  37. }
  38.  
  39.     /* EraseWindow(struct Window *Window):
  40.      *
  41.      *    Fills the interior of a window in the background colour.
  42.      */
  43.  
  44. VOID
  45. EraseWindow(struct Window *Window,UWORD *Pens)
  46. {
  47.     LONG Left,Top,Right,Bottom;
  48.  
  49.     Left    = Window->BorderLeft;
  50.     Top        = Window->BorderTop;
  51.     Right    = Window->Width - (Window->BorderRight + 1);
  52.     Bottom    = Window->Height - (Window->BorderBottom + 1);
  53.  
  54.     if(Pens)
  55.     {
  56.         SetPens(RPort,Pens[BACKGROUNDPEN],0,JAM1);
  57.  
  58.         RectFill(Window->RPort,Left,Top,Right,Bottom);
  59.     }
  60.     else
  61.         EraseRect(Window->RPort,Left,Top,Right,Bottom);
  62. }
  63.  
  64.     /* GetListMaxPen(UWORD *Pens):
  65.      *
  66.      *    Calculates the maximum pen number index to be
  67.      *    used for listview text rendering.
  68.      */
  69.  
  70. LONG
  71. GetListMaxPen(UWORD *Pens)
  72. {
  73.     STATIC BYTE PenTable[] =
  74.     {
  75.         TEXTPEN,
  76.         BACKGROUNDPEN,
  77.         FILLTEXTPEN,
  78.         FILLPEN,
  79.         SHADOWPEN,
  80.         HIGHLIGHTTEXTPEN,
  81.     };
  82.  
  83.     LONG Max,Pen,i;
  84.  
  85.     for(i = 0, Max = -1 ; i < NUM_ELEMENTS(PenTable) ; i++)
  86.     {
  87.         Pen = Pens[PenTable[i]];
  88.  
  89.         if(Pen > Max)
  90.             Max = Pen;
  91.     }
  92.  
  93.     return(Max);
  94. }
  95.  
  96.     /* FillBox(struct RastPort *RPort,LONG Left,LONG Top,LONG Width,LONG Height):
  97.      *
  98.      *    Fill a rectangular area with the current foregroung colour.
  99.      */
  100.  
  101. VOID
  102. FillBox(struct RastPort *RPort,LONG Left,LONG Top,LONG Width,LONG Height)
  103. {
  104.     if(Width > 0 && Height > 0)
  105.         RectFill(RPort,Left,Top,Left + Width - 1,Top + Height - 1);
  106. }
  107.  
  108. VOID
  109. FillWindowBox(struct Window *Window,LONG Left,LONG Top,LONG Width,LONG Height)
  110. {
  111.     if(Left + Width > WindowWidth)
  112.         Width = WindowWidth - Left - 1;
  113.  
  114.     if(Top + Height > WindowHeight)
  115.         Height = WindowHeight - Top - 1;
  116.  
  117.     if(Width > 0 && Height > 0)
  118.     {
  119.         Left    += Window->BorderLeft;
  120.         Top        += Window->BorderTop;
  121.  
  122.         RectFill(Window->RPort,Left,Top,Left + Width - 1,Top + Height - 1);
  123.     }
  124. }
  125.  
  126.     /* PlaceText(struct RastPort *RPort,LONG Left,LONG Top,STRPTR String,LONG Len):
  127.      *
  128.      *    Print some text at a specific position.
  129.      */
  130.  
  131. VOID
  132. PlaceText(struct RastPort *RPort,LONG Left,LONG Top,STRPTR String,LONG Len)
  133. {
  134.     Move(RPort,Left,Top + RPort->TxBaseline);
  135.     Text(RPort,String,Len);
  136. }
  137.  
  138.     /* SetPens(struct RastPort *RPort,ULONG APen,ULONG BPen,ULONG DrMd):
  139.      *
  140.      *    Set rendering attributes.
  141.      */
  142.  
  143. VOID
  144. SetPens(struct RastPort *RPort,ULONG APen,ULONG BPen,ULONG DrMd)
  145. {
  146.     if(Kick30)
  147.         SetABPenDrMd(RPort,APen,BPen,DrMd);
  148.     else
  149.     {
  150.         if(APen != RPort->FgPen)
  151.             SetAPen(RPort,APen);
  152.  
  153.         if(BPen != RPort->BgPen)
  154.             SetBPen(RPort,BPen);
  155.  
  156.         if(DrMd != RPort->DrawMode)
  157.             SetDrMd(RPort,DrMd);
  158.     }
  159. }
  160.  
  161.     /* Atol(STRPTR Buffer):
  162.      *
  163.      *    Convert ASCII representation to long word.
  164.      */
  165.  
  166. LONG
  167. Atol(STRPTR Buffer)
  168. {
  169.     LONG Result;
  170.  
  171.     StrToLong(Buffer,&Result);
  172.  
  173.     return(Result);
  174. }
  175.  
  176.     /* StripSpaces(STRPTR String):
  177.      *
  178.      *    Strip leading and trailing spaces from a string.
  179.      */
  180.  
  181. VOID
  182. StripSpaces(STRPTR String)
  183. {
  184.     if(String)
  185.     {
  186.         STRPTR To;
  187.         LONG Len;
  188.  
  189.         To = String;
  190.  
  191.         while(*String == ' ')
  192.             String++;
  193.  
  194.         if(Len = strlen(String))
  195.         {
  196.             while(Len > 0 && String[Len - 1] == ' ')
  197.                 Len--;
  198.  
  199.             while(Len--)
  200.                 *To++ = *String++;
  201.         }
  202.  
  203.         *To = 0;
  204.     }
  205. }
  206.  
  207.     /* ReplaceWindowInfo(struct WindowInfo *NewInfo):
  208.      *
  209.      *    Drop the window info into the right place.
  210.      */
  211.  
  212. VOID
  213. ReplaceWindowInfo(struct WindowInfo *NewInfo)
  214. {
  215.     LONG i;
  216.  
  217.     ObtainSemaphore(&WindowInfoSemaphore);
  218.  
  219.     for(i = 0 ; WindowInfoTable[i].ID != -1 ; i++)
  220.     {
  221.         if(WindowInfoTable[i].ID == NewInfo->ID)
  222.         {
  223.             CopyMem(NewInfo,&WindowInfoTable[i],sizeof(struct WindowInfo));
  224.  
  225.             break;
  226.         }
  227.     }
  228.  
  229.     ReleaseSemaphore(&WindowInfoSemaphore);
  230. }
  231.  
  232.     /* PutWindowInfo():
  233.      *
  234.      *    Store window size and position relative to
  235.      *    the main window.
  236.      */
  237.  
  238. VOID
  239. PutWindowInfo(LONG ID,LONG Left,LONG Top,LONG Width,LONG Height)
  240. {
  241.     LONG WindowLeft,WindowTop,WindowWidth,WindowHeight;
  242.     struct WindowInfo *Info;
  243.     ULONG IntuiLock;
  244.     LONG i;
  245.  
  246.     ObtainSemaphore(&WindowInfoSemaphore);
  247.  
  248.     for(i = 0 ; WindowInfoTable[i].ID != -1 ; i++)
  249.     {
  250.         if(WindowInfoTable[i].ID == ID)
  251.         {
  252.             Info = &WindowInfoTable[i];
  253.  
  254.             break;
  255.         }
  256.     }
  257.  
  258.     IntuiLock = LockIBase(NULL);
  259.  
  260.     WindowLeft        = Window->LeftEdge;
  261.     WindowTop        = Window->TopEdge;
  262.     WindowWidth        = Window->Width;
  263.     WindowHeight    = Window->Height;
  264.  
  265.     UnlockIBase(IntuiLock);
  266.  
  267.     Info->WindowFlags = NULL;
  268.  
  269.     if(WindowWidth == Width && WindowLeft == Left)
  270.         Info->WindowFlags |= WC_EXPANDWIDTH;
  271.     else
  272.     {
  273.         if(Left == WindowLeft + WindowWidth)
  274.             Info->WindowFlags |= WC_ALIGNSIDE;
  275.  
  276.         if(WindowLeft == Left)
  277.             Info->WindowFlags |= WC_ALIGNLEFT;
  278.  
  279.         if(WindowLeft + WindowWidth == Left + Width)
  280.             Info->WindowFlags |= WC_ALIGNRIGHT;
  281.     }
  282.  
  283.     if(WindowHeight == Height && WindowTop + Window->BorderTop == Top)
  284.         Info->WindowFlags |= WC_EXPANDHEIGHT;
  285.     else
  286.     {
  287.         if(Top == WindowTop + WindowHeight)
  288.             Info->WindowFlags |= WC_ALIGNBELOW;
  289.  
  290.         if(Top == WindowTop + Window->BorderTop)
  291.             Info->WindowFlags |= WC_ALIGNTOP;
  292.  
  293.         if(WindowTop + WindowHeight == Top + Height)
  294.             Info->WindowFlags |= WC_ALIGNBOTTOM;
  295.     }
  296.  
  297.     Info->Left        = Left;
  298.     Info->Top        = Top;
  299.     Info->Width        = Width;
  300.     Info->Height    = Height;
  301.  
  302.     ReleaseSemaphore(&WindowInfoSemaphore);
  303. }
  304.  
  305.     /* GetWindowInfo():
  306.      *
  307.      *    Set the window size and position in relation to
  308.      *    the main window.
  309.      */
  310.  
  311. VOID
  312. GetWindowInfo(LONG ID,LONG *Left,LONG *Top,LONG *Width,LONG *Height,LONG DefWidth,LONG DefHeight)
  313. {
  314.     LONG WindowLeft,WindowTop,WindowWidth,WindowHeight;
  315.     struct WindowInfo *Info;
  316.     ULONG IntuiLock;
  317.     LONG i;
  318.  
  319.     SafeObtainSemaphoreShared(&WindowInfoSemaphore);
  320.  
  321.     Info = NULL;
  322.  
  323.     for(i = 0 ; WindowInfoTable[i].ID != -1 ; i++)
  324.     {
  325.         if(WindowInfoTable[i].ID == ID)
  326.         {
  327.             Info = &WindowInfoTable[i];
  328.  
  329.             break;
  330.         }
  331.     }
  332.  
  333.     if(Info && ID == WINDOW_MAIN)
  334.     {
  335.         *Left    = Info->Left;
  336.         *Top    = Info->Top;
  337.         *Width    = Info->Width;
  338.         *Height    = Info->Height;
  339.     }
  340.     else
  341.     {
  342.         if(Window)
  343.         {
  344.             IntuiLock = LockIBase(NULL);
  345.  
  346.             WindowLeft        = Window->LeftEdge;
  347.             WindowTop        = Window->TopEdge;
  348.             WindowWidth        = Window->Width;
  349.             WindowHeight    = Window->Height;
  350.  
  351.             UnlockIBase(IntuiLock);
  352.  
  353.             if(DefWidth && DefWidth < WindowWidth / 2)
  354.                 DefWidth = WindowWidth / 2;
  355.  
  356.             if(DefHeight && DefHeight < WindowHeight / 2)
  357.                 DefHeight = WindowHeight / 2;
  358.         }
  359.  
  360.         if(*Width)
  361.         {
  362.             if(Info->Width)
  363.                 *Left = Info->Left;
  364.             else
  365.                 *Left = WindowLeft + (WindowWidth - *Width) / 2;
  366.         }
  367.         else
  368.         {
  369.             if(DefWidth && !Info->Width)
  370.             {
  371.                 *Width    = DefWidth;
  372.                 *Left    = WindowLeft + (WindowWidth - *Width) / 2;
  373.             }
  374.             else
  375.             {
  376.                 if(Info->Width)
  377.                 {
  378.                     *Width    = Info->Width;
  379.                     *Left    = Info->Left;
  380.                 }
  381.                 else
  382.                 {
  383.                     *Width    = WindowWidth;
  384.                     *Left    = WindowLeft;
  385.                 }
  386.             }
  387.         }
  388.  
  389.         if(*Height)
  390.         {
  391.             if(Info->Height)
  392.                 *Top = Info->Top;
  393.             else
  394.                 *Top = WindowTop + (WindowHeight - *Height) / 2;
  395.         }
  396.         else
  397.         {
  398.             if(DefHeight && !Info->Height)
  399.             {
  400.                 *Height    = DefHeight;
  401.                 *Top    = WindowTop + (WindowHeight - *Height) / 2;
  402.             }
  403.             else
  404.             {
  405.                 if(Info->Height)
  406.                 {
  407.                     *Height    = Info->Height;
  408.                     *Top    = Info->Top;
  409.                 }
  410.                 else
  411.                 {
  412.                     *Height    = WindowHeight;
  413.                     *Top    = WindowTop;
  414.                 }
  415.             }
  416.         }
  417.  
  418.         if(Info->WindowFlags & WC_ALIGNSIDE)
  419.             *Left = WindowLeft + WindowWidth;
  420.  
  421.         if(Info->WindowFlags & WC_ALIGNBELOW)
  422.             *Top = WindowTop + WindowHeight;
  423.  
  424.         if(Info->WindowFlags & WC_ALIGNLEFT)
  425.             *Left = WindowLeft;
  426.  
  427.         if(Info->WindowFlags & WC_ALIGNTOP)
  428.             *Top = WindowTop;
  429.  
  430.         if(Info->WindowFlags & WC_ALIGNRIGHT)
  431.             *Left = WindowLeft + WindowWidth - *Width;
  432.  
  433.         if(Info->WindowFlags & WC_ALIGNBOTTOM)
  434.             *Top = WindowTop + WindowHeight - *Height;
  435.  
  436.         if(Info->WindowFlags & WC_EXPANDWIDTH)
  437.             *Width = WindowWidth;
  438.  
  439.         if(Info->WindowFlags & WC_EXPANDHEIGHT)
  440.             *Height = WindowHeight;
  441.  
  442.         if(*Top == WindowTop && *Left == WindowLeft)
  443.         {
  444.             LONG TitleHeight = Window->BorderTop;
  445.  
  446.             if(*Height == WindowHeight)
  447.                 *Height -= TitleHeight;
  448.  
  449.             *Top += TitleHeight;
  450.         }
  451.     }
  452.  
  453.     ReleaseSemaphore(&WindowInfoSemaphore);
  454. }
  455.  
  456.     /* GetBitMapDepth(struct BitMap *BitMap):
  457.      *
  458.      *    Return the depth of a BitMap.
  459.      */
  460.  
  461. LONG
  462. GetBitMapDepth(struct BitMap *BitMap)
  463. {
  464.     LONG Depth;
  465.  
  466.     if(Kick30)
  467.         Depth = (LONG)GetBitMapAttr(BitMap,BMA_DEPTH);
  468.     else
  469.         Depth = BitMap->Depth;
  470.  
  471.     if(Depth > 8)
  472.         Depth = 8;
  473.  
  474.     return(Depth);
  475. }
  476.  
  477.     /* GetDPI(ULONG Mode,ULONG *X_DPI,ULONG *Y_DPI):
  478.      *
  479.      *    Get screen DPI resolution values.
  480.      */
  481.  
  482. VOID
  483. GetDPI(ULONG Mode,ULONG *X_DPI,ULONG *Y_DPI)
  484. {
  485.     struct DisplayInfo DisplayInfo;
  486.  
  487.     *X_DPI = *Y_DPI = 72;
  488.  
  489.     if(GetDisplayInfoData(NULL,(APTR)&DisplayInfo,sizeof(struct DisplayInfo),DTAG_DISP,Mode))
  490.     {
  491.         if(DisplayInfo.PixelSpeed && DisplayInfo.Resolution.x && DisplayInfo.Resolution.y)
  492.         {
  493.             *X_DPI = (35 * 140) / DisplayInfo.PixelSpeed;
  494.             *Y_DPI = (*X_DPI * DisplayInfo.Resolution.x) / DisplayInfo.Resolution.y;
  495.         }
  496.     }
  497. }
  498.  
  499.     /* AddProtection(STRPTR FileName,ULONG Mask):
  500.      *
  501.      *    Set bits in the protection mask of a file.
  502.      */
  503.  
  504. VOID
  505. AddProtection(STRPTR Name,ULONG Mask)
  506. {
  507.     BPTR FileLock;
  508.     D_S(struct FileInfoBlock,FileInfo);
  509.  
  510.     if(FileLock = Lock(Name,ACCESS_READ))
  511.     {
  512.         if(Examine(FileLock,FileInfo))
  513.         {
  514.             UnLock(FileLock);
  515.  
  516.             if(Mask == FIBF_EXECUTE)
  517.                 Mask |= FileInfo->fib_Protection & ~(FIBF_OTR_EXECUTE|FIBF_GRP_EXECUTE);
  518.             else
  519.                 Mask |= FileInfo->fib_Protection;
  520.  
  521.             SetProtection(Name,Mask);
  522.         }
  523.         else
  524.             UnLock(FileLock);
  525.     }
  526. }
  527.  
  528.     /* GetPubScreenName(struct Screen *Screen,STRPTR Name):
  529.      *
  530.      *    Get the name of a public screen.
  531.      */
  532.  
  533. BOOL
  534. GetPubScreenName(struct Screen *Screen,STRPTR Name)
  535. {
  536.     struct List                *PubScreenList;
  537.     struct PubScreenNode    *ScreenNode;
  538.     BOOL                     GotIt;
  539.  
  540.     PubScreenList = LockPubScreenList();
  541.  
  542.     for(ScreenNode = (struct PubScreenNode *)PubScreenList->lh_Head, GotIt = FALSE ; !GotIt && ScreenNode->psn_Node.ln_Succ ; ScreenNode = (struct PubScreenNode *)ScreenNode->psn_Node.ln_Succ)
  543.     {
  544.         if(ScreenNode->psn_Screen == Screen)
  545.         {
  546.             strcpy(Name,ScreenNode->psn_Node.ln_Name);
  547.             GotIt = TRUE;
  548.         }
  549.     }
  550.  
  551.     UnlockPubScreenList();
  552.  
  553.     return(GotIt);
  554. }
  555.  
  556.     /* InitSinglePort(struct MsgPort *Port):
  557.      *
  558.      *    Initialize a plain MsgPort (as created on the stack) for
  559.      *    usage. Don't try this at home, kids!
  560.      */
  561.  
  562. VOID
  563. InitSinglePort(struct MsgPort *Port)
  564. {
  565.     memset(Port,0,sizeof(struct MsgPort));
  566.  
  567.     Port->mp_Flags        = PA_SIGNAL;
  568.     Port->mp_SigBit        = SIGB_SINGLE;
  569.     Port->mp_SigTask    = FindTask(NULL);
  570.  
  571.     NewList(&Port->mp_MsgList);
  572. }
  573.  
  574.     /* GoodStream(BPTR Stream):
  575.      *
  576.      *    Check to see whether the current input file
  577.      *    is an interactive stream.
  578.      */
  579.  
  580. BOOL
  581. GoodStream(BPTR Stream)
  582. {
  583.     if(!Stream)
  584.         Stream = Input();
  585.  
  586.     if(Stream)
  587.     {
  588.         struct FileHandle *Handle = (struct FileHandle *)BADDR(Stream);
  589.  
  590.         if(Handle->fh_Type)
  591.         {
  592.             if(IsInteractive(Stream))
  593.                 return(TRUE);
  594.         }
  595.     }
  596.  
  597.     return(FALSE);
  598. }
  599.  
  600.     /* GetProgramIcon():
  601.      *
  602.      *    Try to find the icon of the program.
  603.      */
  604.  
  605. struct DiskObject *
  606. GetProgramIcon()
  607. {
  608.     struct DiskObject *Icon = NULL;
  609.  
  610.         /* Run from Workbench? */
  611.  
  612.     if(WBenchMsg)
  613.     {
  614.             /* Sanity check. */
  615.  
  616.         if(WBenchMsg->sm_ArgList)
  617.         {
  618.                 /* Yet another sanity check. */
  619.  
  620.             if(WBenchMsg->sm_ArgList->wa_Name)
  621.             {
  622.                     /* Try to find the icon in the current directory. */
  623.  
  624.                 if(Icon = GetDiskObjectNew(WBenchMsg->sm_ArgList->wa_Name))
  625.                 {
  626.                     if(Icon->do_Type != WBTOOL)
  627.                     {
  628.                         FreeDiskObject(Icon);
  629.  
  630.                         Icon = NULL;
  631.                     }
  632.                 }
  633.  
  634.                 if(!Icon)
  635.                 {
  636.                     BPTR NewLock;
  637.  
  638.                         /* Move to the directory the
  639.                          * program was run from.
  640.                          */
  641.  
  642.                     if(NewLock = Lock("PROGDIR:",ACCESS_READ))
  643.                     {
  644.                         BPTR OldLock;
  645.  
  646.                         OldLock = CurrentDir(NewLock);
  647.  
  648.                             /* Try to fetch the icon, use the
  649.                              * default name if necessary.
  650.                              */
  651.  
  652.                         if(Icon = GetDiskObjectNew(WBenchMsg->sm_ArgList->wa_Name))
  653.                         {
  654.                             if(Icon->do_Type != WBTOOL)
  655.                             {
  656.                                 FreeDiskObject(Icon);
  657.  
  658.                                 Icon = NULL;
  659.                             }
  660.                         }
  661.  
  662.                         if(!Icon)
  663.                         {
  664.                             if(Icon = GetDiskObjectNew("term"))
  665.                             {
  666.                                 if(Icon->do_Type != WBTOOL)
  667.                                 {
  668.                                     FreeDiskObject(Icon);
  669.  
  670.                                     Icon = NULL;
  671.                                 }
  672.                             }
  673.                         }
  674.  
  675.                         CurrentDir(OldLock);
  676.  
  677.                         UnLock(NewLock);
  678.                     }
  679.                 }
  680.             }
  681.         }
  682.     }
  683.  
  684.         /* Still no success. */
  685.  
  686.     if(!Icon)
  687.     {
  688.             /* Use the default names. */
  689.  
  690.         if(Icon = GetDiskObjectNew("term"))
  691.         {
  692.             if(Icon->do_Type != WBTOOL)
  693.             {
  694.                 FreeDiskObject(Icon);
  695.  
  696.                 Icon = NULL;
  697.             }
  698.         }
  699.  
  700.         if(!Icon)
  701.         {
  702.             if(Icon = GetDiskObjectNew("PROGDIR:term"))
  703.             {
  704.                 if(Icon->do_Type != WBTOOL)
  705.                 {
  706.                     FreeDiskObject(Icon);
  707.  
  708.                     Icon = NULL;
  709.                 }
  710.             }
  711.         }
  712.     }
  713.  
  714.     return(Icon);
  715. }
  716.  
  717.     /* GetPenIndex(LONG Pen):
  718.      *
  719.      *    Get the table index corresponding to an on-screen
  720.      *    text rendering pen.
  721.      */
  722.  
  723. LONG
  724. GetPenIndex(LONG Pen)
  725. {
  726.     LONG i,Result = 0;
  727.  
  728.     for(i = 0 ; i < 16 ; i++)
  729.     {
  730.         if(MappedPens[0][i] == Pen)
  731.         {
  732.             Result = i;
  733.             break;
  734.         }
  735.     }
  736.  
  737.     return(Result);
  738. }
  739.  
  740.     /* GetScreenWidth(struct Window *Window):
  741.      *
  742.      *    Query the current screen width.
  743.      */
  744.  
  745. LONG
  746. GetScreenWidth(struct Window *Window)
  747. {
  748.     if(Window)
  749.     {
  750.         if(Window->Width > ScreenWidth || Window->LeftEdge < -Window->WScreen->LeftEdge || Window->LeftEdge + Window->WScreen->LeftEdge + Window->Width > ScreenWidth)
  751.             return(ScreenWidth);
  752.         else
  753.             return(Window->Width - (Window->BorderLeft + Window->BorderRight));
  754.     }
  755.     else
  756.         return(ScreenWidth);
  757. }
  758.  
  759.     /* GetScreenHeight(struct Window *Window):
  760.      *
  761.      *    Query the current screen height.
  762.      */
  763.  
  764. LONG
  765. GetScreenHeight(struct Window *Window)
  766. {
  767.     if(Window)
  768.     {
  769.         if(Window->Height > ScreenHeight || Window->TopEdge < -Window->WScreen->TopEdge || Window->TopEdge + Window->WScreen->TopEdge + Window->Height > ScreenHeight)
  770.             return(ScreenHeight);
  771.         else
  772.             return(Window->Height - (Window->BorderTop + Window->BorderBottom));
  773.     }
  774.     else
  775.         return(ScreenHeight);
  776. }
  777.  
  778.     /* GetLeft(struct Screen *Screen):
  779.      *
  780.      *    Get the screen left edge.
  781.      */
  782.  
  783. STATIC LONG
  784. GetLeft(struct Screen *Screen)
  785. {
  786.     if(Screen->LeftEdge >= 0)
  787.         return(0);
  788.     else
  789.         return(-Screen->LeftEdge);
  790. }
  791.  
  792.     /* GetScreenLeft(struct Window *Window):
  793.      *
  794.      *    Query the current screen left edge.
  795.      */
  796.  
  797. LONG
  798. GetScreenLeft(struct Window *Window)
  799. {
  800.     if(Window)
  801.     {
  802.         if(Window->Width > ScreenWidth || Window->LeftEdge < -Window->WScreen->LeftEdge || Window->LeftEdge + Window->WScreen->LeftEdge + Window->Width > ScreenWidth)
  803.             return(GetLeft(Window->WScreen));
  804.         else
  805.             return(Window->LeftEdge + Window->BorderLeft);
  806.     }
  807.     else
  808.     {
  809.         struct Screen *PubScreen = LockPubScreen(NULL);
  810.         LONG Result;
  811.  
  812.         Result = GetLeft(PubScreen ? PubScreen : SharedScreen);
  813.  
  814.         UnlockPubScreen(NULL,PubScreen);
  815.  
  816.         return(Result);
  817.     }
  818. }
  819.  
  820.     /* OldGetAPen(struct RastPort *RPort):
  821.      *
  822.      *    Query the current primary rendering colour (old style).
  823.      */
  824.  
  825. ULONG
  826. OldGetAPen(struct RastPort *RPort)
  827. {
  828.     return((ULONG)RPort->FgPen);
  829. }
  830.  
  831.     /* OldGetBPen(struct RastPort *RPort):
  832.      *
  833.      *    Query the current seconary rendering colour (old style).
  834.      */
  835.  
  836. ULONG
  837. OldGetBPen(struct RastPort *RPort)
  838. {
  839.     return((ULONG)RPort->BgPen);
  840. }
  841.  
  842.     /* OldGetDrMd(struct RastPort *RPort):
  843.      *
  844.      *    Query the current drawing mode (old style).
  845.      */
  846.  
  847. ULONG
  848. OldGetDrMd(struct RastPort *RPort)
  849. {
  850.     return((ULONG)RPort->DrawMode);
  851. }
  852.  
  853.     /* OldSetWrMsk(struct RastPort *RPort,ULONG Mask):
  854.      *
  855.      *    Set the rendering plane mask (old style).
  856.      */
  857.  
  858. ULONG
  859. OldSetWrMsk(struct RastPort *RPort,ULONG Mask)
  860. {
  861.     if(UseMasking)
  862.         RPort->Mask = Mask;
  863.  
  864.     return((ULONG)1);
  865. }
  866.  
  867.     /* OldGetWrMsk(struct RastPort *RPort):
  868.      *
  869.      *    Get the rendering plane mask (old style).
  870.      */
  871.  
  872. ULONG
  873. OldGetWrMsk(struct RastPort *RPort)
  874. {
  875.     return(RPort->Mask);
  876. }
  877.  
  878.     /* NewGetAPen(struct RastPort *RPort):
  879.      *
  880.      *    Query the current primary rendering colour (new style).
  881.      */
  882.  
  883. ULONG
  884. NewGetAPen(struct RastPort *RPort)
  885. {
  886.     return(GetAPen(RPort));
  887. }
  888.  
  889.     /* NewGetBPen(struct RastPort *RPort):
  890.      *
  891.      *    Query the current seconary rendering colour (new style).
  892.      */
  893.  
  894. ULONG
  895. NewGetBPen(struct RastPort *RPort)
  896. {
  897.     return(GetBPen(RPort));
  898. }
  899.  
  900.     /* NewGetDrMd(struct RastPort *RPort):
  901.      *
  902.      *    Query the current drawing mode (new style).
  903.      */
  904.  
  905. ULONG
  906. NewGetDrMd(struct RastPort *RPort)
  907. {
  908.     return(GetDrMd(RPort));
  909. }
  910.  
  911.     /* NewSetWrMsk(struct RastPort *RPort,ULONG Mask):
  912.      *
  913.      *    Set the rendering plane mask (new style).
  914.      */
  915.  
  916. ULONG
  917. NewSetWrMsk(struct RastPort *RPort,ULONG Mask)
  918. {
  919.     if(UseMasking)
  920.         return(SetWriteMask(RPort,Mask));
  921.     else
  922.         return((ULONG)1);
  923. }
  924.  
  925.     /* NewGetWrMsk(struct RastPort *RPort):
  926.      *
  927.      *    Get the rendering plane mask (new style).
  928.      */
  929.  
  930. ULONG
  931. NewGetWrMsk(struct RastPort *RPort)
  932. {
  933.     ULONG Mask;
  934.  
  935.     Mask = (ULONG)~0;
  936.  
  937.     GetRPAttrs(RPort,
  938.         RPTAG_WriteMask,&Mask,
  939.     TAG_DONE);
  940.  
  941.     return(Mask);
  942. }
  943.  
  944.     /* SetWait(struct Window *Window):
  945.      *
  946.      *    Set the busy wait mouse pointer.
  947.      */
  948.  
  949. VOID
  950. SetWait(struct Window *Window)
  951. {
  952.     if(GTLayoutBase)
  953.         LT_LockWindow(Window);
  954. }
  955.  
  956.     /* ClrWait(struct Window *Window):
  957.      *
  958.      *    Remove the busy wait mouse pointer.
  959.      */
  960.  
  961. VOID
  962. ClrWait(struct Window *Window)
  963. {
  964.     if(GTLayoutBase)
  965.         LT_UnlockWindow(Window);
  966. }
  967.  
  968.     /* GetModeName(ULONG Mode):
  969.      *
  970.      *    Get the name of a display mode.
  971.      */
  972.  
  973. VOID
  974. GetModeName(ULONG Mode,STRPTR Buffer,LONG BufferSize)
  975. {
  976.     struct NameInfo    NameInfo;
  977.  
  978.     if(GetDisplayInfoData(NULL,(APTR)&NameInfo,sizeof(struct NameInfo),DTAG_NAME,Mode))
  979.         LimitedStrcpy(BufferSize,Buffer,NameInfo.Name);
  980.     else
  981.     {
  982.         struct DimensionInfo DimensionInfo;
  983.  
  984.         if(GetDisplayInfoData(NULL,(APTR)&DimensionInfo,sizeof(struct DimensionInfo),DTAG_DIMS,Mode))
  985.         {
  986.             STRPTR MonitorName;
  987.  
  988.             switch(Mode & MONITOR_ID_MASK)
  989.             {
  990.                 case NTSC_MONITOR_ID:
  991.  
  992.                     MonitorName = "NTSC:";
  993.                     break;
  994.  
  995.                 case PAL_MONITOR_ID:
  996.  
  997.                     MonitorName = "PAL:";
  998.                     break;
  999.  
  1000.                 case VGA_MONITOR_ID:
  1001.  
  1002.                     MonitorName = "VGA:";
  1003.                     break;
  1004.  
  1005.                 case A2024_MONITOR_ID:
  1006.  
  1007.                     MonitorName = "A2024:";
  1008.                     break;
  1009.  
  1010.                 default:
  1011.  
  1012.                     MonitorName = "";
  1013.                     break;
  1014.             }
  1015.  
  1016.             LimitedSPrintf(BufferSize,Buffer,"%s%ldx%ld",MonitorName,DimensionInfo.TxtOScan.MaxX - DimensionInfo.TxtOScan.MinX + 1,DimensionInfo.TxtOScan.MaxY - DimensionInfo.TxtOScan.MinY + 1);
  1017.         }
  1018.         else
  1019.             LimitedStrcpy(BufferSize,Buffer,LocaleString(MSG_SCREENPANEL_UNKNOWN_TXT));
  1020.     }
  1021. }
  1022.  
  1023.     /* ModeOkay(ULONG ID):
  1024.      *
  1025.      *    Checks whether a display mode ID will do for deep
  1026.      *    screen bitmaps.
  1027.      */
  1028.  
  1029. BOOL
  1030. ModeOkay(ULONG ID)
  1031. {
  1032.     struct DimensionInfo DimensionInfo;
  1033.  
  1034.     if(GetDisplayInfoData(NULL,(APTR)&DimensionInfo,sizeof(struct DimensionInfo),DTAG_DIMS,ID))
  1035.     {
  1036.         if(DimensionInfo.MaxDepth >= 4)
  1037.             return(TRUE);
  1038.     }
  1039.  
  1040.     return(FALSE);
  1041. }
  1042.  
  1043.     /* ExtractString():
  1044.      *
  1045.      *    Extracts a string from a list separated by `|' characters.
  1046.      */
  1047.  
  1048. STRPTR
  1049. ExtractString(STRPTR String,STRPTR Destination,BOOL ReturnEnd)
  1050. {
  1051.     STRPTR OldString;
  1052.  
  1053.     if(ReturnEnd)
  1054.         OldString = NULL;
  1055.     else
  1056.         OldString = String;
  1057.  
  1058.     while(*String)
  1059.     {
  1060.         if(*String == '|')
  1061.         {
  1062.             *Destination = 0;
  1063.  
  1064.             String++;
  1065.  
  1066.             if(*String)
  1067.                 return(String);
  1068.             else
  1069.                 return(OldString);
  1070.         }
  1071.         else
  1072.             *Destination++ = *String++;
  1073.     }
  1074.  
  1075.     *Destination = 0;
  1076.  
  1077.     return(OldString);
  1078. }
  1079.  
  1080.     /* RemoveGetNext(struct Node *Node):
  1081.      *
  1082.      *    Remove a node from a list and return the `next'
  1083.      *    node to take its place.
  1084.      */
  1085.  
  1086. struct Node *
  1087. RemoveGetNext(struct Node *Node)
  1088. {
  1089.     struct Node *Next;
  1090.  
  1091.         /* Does the node have a successor? */
  1092.  
  1093.     if(Node->ln_Succ->ln_Succ)
  1094.         Next = Node->ln_Succ;
  1095.     else
  1096.     {
  1097.             /* Does it have a predecessor? */
  1098.  
  1099.         if(Node->ln_Pred->ln_Pred)
  1100.             Next = Node->ln_Pred;
  1101.         else
  1102.             Next = NULL;
  1103.     }
  1104.  
  1105.         /* Remove the old node. */
  1106.  
  1107.     Remove(Node);
  1108.  
  1109.         /* And return the node to take its place. */
  1110.  
  1111.     return(Next);
  1112. }
  1113.  
  1114.     /* GetListSize(struct List *List):
  1115.      *
  1116.      *    Determine the number of entries in a list.
  1117.      */
  1118.  
  1119. LONG
  1120. GetListSize(struct List *List)
  1121. {
  1122.     struct Node *Node;
  1123.     LONG i;
  1124.  
  1125.     for(Node = List->lh_Head, i = 0 ; Node->ln_Succ ; Node = Node->ln_Succ, i++);
  1126.  
  1127.     return(i);
  1128. }
  1129.  
  1130.     /* GetListNode(LONG Offset,struct List *List):
  1131.      *
  1132.      *    Return the n-th Node entry in a standard exec list.
  1133.      */
  1134.  
  1135. struct Node *
  1136. GetListNode(LONG Offset,struct List *List)
  1137. {
  1138.     struct Node *Node;
  1139.     LONG Index;
  1140.  
  1141.     for(Node = List->lh_Head, Index = 0 ; Node->ln_Succ ; Node = Node->ln_Succ, Index++)
  1142.     {
  1143.         if(Index == Offset)
  1144.             return(Node);
  1145.     }
  1146.  
  1147.     return(NULL);
  1148. }
  1149.  
  1150.     /* CreateNode(STRPTR Name):
  1151.      *
  1152.      *    Put a name string into a list node.
  1153.      */
  1154.  
  1155. struct Node *
  1156. CreateNode(STRPTR Name)
  1157. {
  1158.     struct Node *Node;
  1159.  
  1160.     if(Node = (struct Node *)AllocVecPooled(sizeof(struct Node) + strlen(Name) + 1,MEMF_ANY))
  1161.         strcpy(Node->ln_Name = (STRPTR)(Node + 1),Name);
  1162.  
  1163.     return(Node);
  1164. }
  1165.  
  1166.     /* CreateNodeArgs(STRPTR Format,...):
  1167.      *
  1168.      *    Put a name string into a list node, varargs version.
  1169.      */
  1170.  
  1171. struct Node *
  1172. CreateNodeArgs(STRPTR Format,...)
  1173. {
  1174.     UBYTE LocalBuffer[256];
  1175.     struct Node *Node;
  1176.     va_list VarArgs;
  1177.  
  1178.     va_start(VarArgs,Format);
  1179.     LimitedVSPrintf(sizeof(LocalBuffer),LocalBuffer,Format,VarArgs);
  1180.     va_end(VarArgs);
  1181.  
  1182.     if(Node = (struct Node *)AllocVecPooled(sizeof(struct Node) + strlen(LocalBuffer) + 1,MEMF_ANY))
  1183.         strcpy(Node->ln_Name = (STRPTR)(Node + 1),LocalBuffer);
  1184.  
  1185.     return(Node);
  1186. }
  1187.  
  1188.     /* FormatAppend(STRPTR String,STRPTR Format,...):
  1189.      *
  1190.      *    Appends a formatted string to another string.
  1191.      */
  1192.  
  1193. VOID
  1194. FormatAppend(STRPTR String,STRPTR Format,...)
  1195. {
  1196.     va_list VarArgs;
  1197.  
  1198.     String += strlen(String);
  1199.  
  1200.     va_start(VarArgs,Format);
  1201.     VSPrintf(String,Format,VarArgs);
  1202.     va_end(VarArgs);
  1203. }
  1204.  
  1205.     /* FreeList(struct List *List):
  1206.      *
  1207.      *    Remove all nodes from the list
  1208.      *    and free them on the way.
  1209.      */
  1210.  
  1211. VOID
  1212. FreeList(struct List *List)
  1213. {
  1214.     if(List)
  1215.     {
  1216.         struct Node *Node;
  1217.  
  1218.         while(Node = RemHead(List))
  1219.             FreeVecPooled(Node);
  1220.     }
  1221. }
  1222.  
  1223.     /* GetNodeOffset(struct Node *Node,struct List *List):
  1224.      *
  1225.      *    Scan a list for a certain node and return
  1226.      *    its position.
  1227.      */
  1228.  
  1229. LONG
  1230. GetNodeOffset(struct Node *ListNode,struct List *List)
  1231. {
  1232.     if(ListNode && List)
  1233.     {
  1234.         struct Node *Node;
  1235.         LONG Offset;
  1236.  
  1237.         for(Node = List->lh_Head, Offset = 0 ; Node->ln_Succ ; Node = Node->ln_Succ, Offset++)
  1238.         {
  1239.             if(Node == ListNode)
  1240.                 return(Offset);
  1241.         }
  1242.     }
  1243.  
  1244.     return(-1);
  1245. }
  1246.  
  1247.     /* MoveList(struct List *From,struct List *To):
  1248.      *
  1249.      *    Move the contents of a list to a different list.
  1250.      */
  1251.  
  1252. VOID
  1253. MoveList(struct List *From,struct List *To)
  1254. {
  1255.     struct Node *Node;
  1256.  
  1257.     while(Node = RemHead(From))
  1258.         AddTail(To,Node);
  1259. }
  1260.  
  1261.     /* CreateList():
  1262.      *
  1263.      *    Create a small, empty list.
  1264.      */
  1265.  
  1266. struct List *
  1267. CreateList()
  1268. {
  1269.     struct List *List;
  1270.  
  1271.     if(List = (struct List *)AllocVecPooled(sizeof(struct MinList),MEMF_ANY))
  1272.         NewList(List);
  1273.  
  1274.     return(List);
  1275. }
  1276.  
  1277.     /* DeleteList():
  1278.      *
  1279.      *    Free the contents of a list and the list itself.
  1280.      */
  1281.  
  1282. VOID
  1283. DeleteList(struct List *List)
  1284. {
  1285.     if(List)
  1286.     {
  1287.         struct Node *Node,*Next;
  1288.  
  1289.         for(Node = List->lh_Head ; Next = Node->ln_Succ ; Node = Next)
  1290.             FreeVecPooled(Node);
  1291.  
  1292.         FreeVecPooled(List);
  1293.     }
  1294. }
  1295.  
  1296.     /* MoveNode(struct List *List,struct Node *Node,LONG How):
  1297.      *
  1298.      *    Move a list node somewhere.
  1299.      */
  1300.  
  1301. VOID
  1302. MoveNode(struct List *List,struct Node *Node,LONG How)
  1303. {
  1304.     switch(How)
  1305.     {
  1306.         case MOVE_HEAD:
  1307.  
  1308.             if(Node != List->lh_Head)
  1309.             {
  1310.                 Remove(Node);
  1311.  
  1312.                 AddHead(List,Node);
  1313.             }
  1314.  
  1315.             break;
  1316.  
  1317.         case MOVE_PRED:
  1318.  
  1319.             if(Node != List->lh_Head)
  1320.             {
  1321.                 struct Node *Other;
  1322.  
  1323.                 Other = Node->ln_Pred->ln_Pred;
  1324.  
  1325.                 Remove(Node);
  1326.  
  1327.                 Insert(List,Node,Other);
  1328.             }
  1329.  
  1330.             break;
  1331.  
  1332.         case MOVE_SUCC:
  1333.  
  1334.             if(Node != List->lh_TailPred)
  1335.             {
  1336.                 struct Node *Other;
  1337.  
  1338.                 Other = Node->ln_Succ;
  1339.  
  1340.                 Remove(Node);
  1341.  
  1342.                 Insert(List,Node,Other);
  1343.             }
  1344.  
  1345.             break;
  1346.  
  1347.         case MOVE_TAIL:
  1348.  
  1349.             if(Node != List->lh_TailPred)
  1350.             {
  1351.                 Remove(Node);
  1352.  
  1353.                 AddTail(List,Node);
  1354.             }
  1355.  
  1356.             break;
  1357.     }
  1358. }
  1359.  
  1360.     /* LogAction(STRPTR String,...):
  1361.      *
  1362.      *    Write an action to the default log file.
  1363.      */
  1364.  
  1365. VOID
  1366. LogAction(STRPTR String,...)
  1367. {
  1368.     if(Config->CaptureConfig->LogActions && Config->CaptureConfig->LogFileName[0])
  1369.     {
  1370.         UBYTE    DummyBuffer[512];
  1371.         BPTR    File;
  1372.         BOOL    Created;
  1373.  
  1374.         va_list    VarArgs;
  1375.  
  1376.             /* Build a valid string. */
  1377.  
  1378.         va_start(VarArgs,String);
  1379.         LimitedVSPrintf(sizeof(DummyBuffer),DummyBuffer,String,VarArgs);
  1380.         va_end(VarArgs);
  1381.  
  1382.             /* Open the log file. */
  1383.  
  1384.         if(File = OpenToAppend(Config->CaptureConfig->LogFileName,&Created))
  1385.         {
  1386.             if(Created)
  1387.                 FPrintf(File,LocaleString(MSG_TERMAUX_DATE_TIME_ACTION_TXT));
  1388.         }
  1389.  
  1390.             /* The file is open, build the date/time string and
  1391.              * write the log action.
  1392.              */
  1393.  
  1394.         if(File)
  1395.         {
  1396.             UBYTE            DateBuffer[40],
  1397.                             TimeBuffer[40];
  1398.             struct DateTime    DateTime;
  1399.  
  1400.             DateStamp(&DateTime.dat_Stamp);
  1401.  
  1402.             DateTime.dat_Format        = FORMAT_DEF;
  1403.             DateTime.dat_Flags        = NULL;
  1404.             DateTime.dat_StrDay        = NULL;
  1405.             DateTime.dat_StrDate    = DateBuffer;
  1406.             DateTime.dat_StrTime    = TimeBuffer;
  1407.  
  1408.             if(DateToStr(&DateTime))
  1409.             {
  1410.                 StripSpaces(TimeBuffer);
  1411.  
  1412.                 FPrintf(File,"%-9s %8s %s\n",DateBuffer,TimeBuffer,DummyBuffer);
  1413.             }
  1414.  
  1415.                 /* Done! */
  1416.  
  1417.             Close(File);
  1418.         }
  1419.     }
  1420. }
  1421.  
  1422.     /* GetString(STRPTR Prompt,STRPTR Buffer):
  1423.      *
  1424.      *    Get a string from the user, very much the same as xpr_gets.
  1425.      */
  1426.  
  1427. BOOL
  1428. GetString(BOOL LoadGadget,BOOL Password,LONG MaxChars,STRPTR Prompt,STRPTR Buffer)
  1429. {
  1430.     enum    {    GAD_OK=1,GAD_CANCEL,GAD_STRING };
  1431.  
  1432.     struct LayoutHandle    *Handle;
  1433.     UBYTE LocalBuffer[256];
  1434.     BOOL Success = FALSE;
  1435.  
  1436.     if(!MaxChars)
  1437.         MaxChars = sizeof(LocalBuffer) - 1;
  1438.  
  1439.     if(MaxChars > sizeof(LocalBuffer) - 1)
  1440.     {
  1441.         CopyMem(Buffer,LocalBuffer,sizeof(LocalBuffer) - 1);
  1442.  
  1443.         LocalBuffer[sizeof(LocalBuffer) - 1] = 0;
  1444.  
  1445.         MaxChars = sizeof(LocalBuffer) - 1;
  1446.     }
  1447.     else
  1448.         strcpy(LocalBuffer,Buffer);
  1449.  
  1450.     if(!Prompt)
  1451.         Prompt = LocaleString(MSG_TERMXPR_INPUT_REQUIRED_TXT);
  1452.  
  1453.     if(Handle = LT_CreateHandleTags(Window->WScreen,
  1454.         LAHN_LocaleHook,    &LocaleHook,
  1455.     TAG_DONE))
  1456.     {
  1457.         struct Window *PanelWindow;
  1458.  
  1459.         LT_New(Handle,
  1460.             LA_Type,    VERTICAL_KIND,
  1461.         TAG_DONE);
  1462.         {
  1463.             LT_New(Handle,
  1464.                 LA_Type,    VERTICAL_KIND,
  1465.                 LA_LabelText,    Prompt,
  1466.             TAG_DONE);
  1467.             {
  1468.                 if(Password)
  1469.                 {
  1470.                     LT_New(Handle,
  1471.                         LA_Type,        PASSWORD_KIND,
  1472.                         LA_STRPTR,        LocalBuffer,
  1473.                         LA_ID,            GAD_STRING,
  1474.                         LA_Chars,        40,
  1475.                         GTST_MaxChars,    MaxChars,
  1476.                     TAG_DONE);
  1477.                 }
  1478.                 else
  1479.                 {
  1480.                     LT_New(Handle,
  1481.                         LA_Type,        STRING_KIND,
  1482.                         LA_STRPTR,        LocalBuffer,
  1483.                         LA_ID,            GAD_STRING,
  1484.                         LA_Chars,        60,
  1485.                         LAST_Picker,    LoadGadget,
  1486.                     TAG_DONE);
  1487.                 }
  1488.  
  1489.                 LT_EndGroup(Handle);
  1490.             }
  1491.  
  1492.             LT_New(Handle,
  1493.                 LA_Type,VERTICAL_KIND,
  1494.             TAG_DONE);
  1495.             {
  1496.                 LT_New(Handle,
  1497.                     LA_Type,        XBAR_KIND,
  1498.                     LAXB_FullSize,    TRUE,
  1499.                 TAG_DONE);
  1500.  
  1501.                 LT_EndGroup(Handle);
  1502.             }
  1503.  
  1504.             LT_New(Handle,LA_Type,HORIZONTAL_KIND,
  1505.                 LAGR_SameSize,    TRUE,
  1506.                 LAGR_Spread,    TRUE,
  1507.             TAG_DONE);
  1508.             {
  1509.                 LT_New(Handle,
  1510.                     LA_Type,        BUTTON_KIND,
  1511.                     LA_LabelID,        MSG_TERMXPR_OKAY_GAD,
  1512.                     LA_ID,            GAD_OK,
  1513.                     LABT_ReturnKey,    TRUE,
  1514.                     LABT_ExtraFat,    TRUE,
  1515.                 TAG_DONE);
  1516.  
  1517.                 LT_New(Handle,
  1518.                     LA_Type,        BUTTON_KIND,
  1519.                     LA_LabelID,        MSG_GLOBAL_CANCEL_GAD,
  1520.                     LA_ID,            GAD_CANCEL,
  1521.                     LABT_EscKey,    TRUE,
  1522.                     LABT_ExtraFat,    TRUE,
  1523.                 TAG_DONE);
  1524.  
  1525.                 LT_EndGroup(Handle);
  1526.             }
  1527.         }
  1528.  
  1529.         if(PanelWindow = LT_Build(Handle,
  1530.             LAWN_TitleID,        MSG_GLOBAL_ENTER_TEXT_TXT,
  1531.             LAWN_HelpHook,        &GuideHook,
  1532.             LAWN_Parent,        Window,
  1533.             WA_DepthGadget,        TRUE,
  1534.             WA_DragBar,            TRUE,
  1535.             WA_RMBTrap,            TRUE,
  1536.             WA_Activate,        TRUE,
  1537.             WA_SimpleRefresh,    TRUE,
  1538.         TAG_DONE))
  1539.         {
  1540.             struct IntuiMessage    *Message;
  1541.             BOOL                 Done = FALSE;
  1542.             ULONG                 MsgClass;
  1543.             UWORD                 MsgCode;
  1544.             struct Gadget        *MsgGadget;
  1545.  
  1546.             LT_Activate(Handle,GAD_STRING);
  1547.  
  1548.             PushWindow(PanelWindow);
  1549.  
  1550.             LT_ShowWindow(Handle,TRUE);
  1551.  
  1552.             do
  1553.             {
  1554.                 if(Wait(PORTMASK(PanelWindow->UserPort) | SIG_BREAK) & SIG_BREAK)
  1555.                     break;
  1556.  
  1557.                 while(Message = (struct IntuiMessage *)LT_GetIMsg(Handle))
  1558.                 {
  1559.                     MsgClass    = Message->Class;
  1560.                     MsgCode        = Message->Code;
  1561.                     MsgGadget    = (struct Gadget *)Message->IAddress;
  1562.  
  1563.                     LT_ReplyIMsg(Message);
  1564.  
  1565.                     if(MsgClass == IDCMP_GADGETUP)
  1566.                     {
  1567.                         switch(MsgGadget->GadgetID)
  1568.                         {
  1569.                             case GAD_STRING:
  1570.  
  1571.                                 if(MsgCode == '\r')
  1572.                                 {
  1573.                                     LT_UpdateStrings(Handle);
  1574.  
  1575.                                     strcpy(Buffer,LocalBuffer);
  1576.  
  1577.                                     Success = Done = TRUE;
  1578.  
  1579.                                     LT_PressButton(Handle,GAD_OK);
  1580.                                 }
  1581.  
  1582.                                 break;
  1583.  
  1584.                             case GAD_OK:
  1585.  
  1586.                                 LT_UpdateStrings(Handle);
  1587.  
  1588.                                 strcpy(Buffer,LocalBuffer);
  1589.  
  1590.                                 Success = Done = TRUE;
  1591.                                 break;
  1592.  
  1593.                             case GAD_CANCEL:
  1594.  
  1595.                                 Done = TRUE;
  1596.                                 break;
  1597.                         }
  1598.                     }
  1599.  
  1600.                     if(MsgClass == IDCMP_IDCMPUPDATE && MsgGadget->GadgetID == GAD_STRING)
  1601.                     {
  1602.                         UBYTE DummyBuffer[MAX_FILENAME_LENGTH];
  1603.                         struct FileRequester *FileRequest;
  1604.  
  1605.                         strcpy(DummyBuffer,LocalBuffer);
  1606.  
  1607.                         if(FileRequest = OpenSingleFile(PanelWindow,LocaleString(MSG_TERMAUX_LOAD_FILE_TXT),NULL,NULL,DummyBuffer,sizeof(DummyBuffer)))
  1608.                         {
  1609.                             FreeAslRequest(FileRequest);
  1610.  
  1611.                             LT_SetAttributes(Handle,GAD_STRING,
  1612.                                 GTST_String,    DummyBuffer,
  1613.                             TAG_DONE);
  1614.                         }
  1615.                     }
  1616.                 }
  1617.             }
  1618.             while(!Done);
  1619.  
  1620.             PopWindow();
  1621.         }
  1622.  
  1623.         LT_DeleteHandle(Handle);
  1624.     }
  1625.  
  1626.     return(Success);
  1627. }
  1628.  
  1629.     /* WakeUp(struct Window *Window,LONG Sound):
  1630.      *
  1631.      *    Pop a window to the front and alert the user.
  1632.      */
  1633.  
  1634. VOID
  1635. WakeUp(struct Window *Window,LONG Sound)
  1636. {
  1637.     if(Window)
  1638.     {
  1639.         if(Config->MiscConfig->AlertMode == ALERT_SCREEN || Config->MiscConfig->AlertMode == ALERT_BEEP_SCREEN)
  1640.         {
  1641.             if(Window->WScreen->LeftEdge > 0)
  1642.             {
  1643.                 if(Window->WScreen->TopEdge > 0)
  1644.                     MoveScreen(Window->WScreen,-Window->WScreen->LeftEdge,-Window->WScreen->TopEdge);
  1645.                 else
  1646.                     MoveScreen(Window->WScreen,-Window->WScreen->LeftEdge,0);
  1647.             }
  1648.             else
  1649.             {
  1650.                 if(Window->WScreen->TopEdge > 0)
  1651.                     MoveScreen(Window->WScreen,0,-Window->WScreen->TopEdge);
  1652.             }
  1653.  
  1654.             WindowToFront(Window);
  1655.  
  1656.             ScreenToFront(Window->WScreen);
  1657.         }
  1658.     }
  1659.  
  1660.     if(Sound != SOUND_BELL || Config->MiscConfig->AlertMode == ALERT_BEEP || Config->MiscConfig->AlertMode == ALERT_BEEP_SCREEN)
  1661.         SoundPlay(Sound);
  1662. }
  1663.  
  1664.     /* BlockWindows():
  1665.      *
  1666.      *    Block the main window and the status window (i.e. disable
  1667.      *    the menu and attach a wait pointer).
  1668.      */
  1669.  
  1670. VOID
  1671. BlockWindows()
  1672. {
  1673.     if(!(BlockNestCount++))
  1674.     {
  1675.         LT_LockWindow(Window);
  1676.         LT_LockWindow(StatusWindow);
  1677.         LT_LockWindow(FastWindow);
  1678.         LT_LockWindow(MatrixWindow);
  1679.  
  1680.         WeAreBlocking = TRUE;
  1681.  
  1682.         SetQueueDiscard(SpecialQueue,TRUE);
  1683.  
  1684.         GhostCursor();
  1685.     }
  1686. }
  1687.  
  1688.     /* ReleaseWindows():
  1689.      *
  1690.      *    Reenable the menus and clear the wait pointer.
  1691.      */
  1692.  
  1693. VOID
  1694. ReleaseWindows()
  1695. {
  1696.     if(BlockNestCount == 1)
  1697.     {
  1698.         LT_UnlockWindow(Window);
  1699.         LT_UnlockWindow(StatusWindow);
  1700.         LT_UnlockWindow(FastWindow);
  1701.         LT_UnlockWindow(MatrixWindow);
  1702.  
  1703.         WeAreBlocking = FALSE;
  1704.  
  1705.         SetQueueDiscard(SpecialQueue,FALSE);
  1706.  
  1707.         if(Window)
  1708.         {
  1709.             Forbid();
  1710.  
  1711.             if(Window->Flags & WFLG_WINDOWACTIVE)
  1712.                 NormalCursor();
  1713.  
  1714.             Permit();
  1715.         }
  1716.     }
  1717.  
  1718.     if(BlockNestCount)
  1719.         BlockNestCount--;
  1720. }
  1721.  
  1722.     /* LineRead(BPTR File,STRPTR Buffer,LONG MaxChars):
  1723.      *
  1724.      *    Read a few bytes from a file (à la gets).
  1725.      */
  1726.  
  1727. LONG
  1728. LineRead(BPTR File,STRPTR Buffer,LONG MaxChars)
  1729. {
  1730.     STATIC UBYTE    Data[1024];
  1731.     STATIC LONG        ReadIndex,ReadLen;
  1732.  
  1733.     LONG BytesRead = 0;
  1734.  
  1735.     if(File)
  1736.     {
  1737.         LONG i;
  1738.  
  1739.         for(i = 0 ; i < MaxChars ; i++)
  1740.         {
  1741.             if(ReadIndex >= ReadLen)
  1742.             {
  1743.                 ReadLen = Read(File,Data,sizeof(Data));
  1744.  
  1745.                 ReadIndex = 0;
  1746.  
  1747.                 if(ReadLen <= 0)
  1748.                 {
  1749.                     Buffer[i] = 0;
  1750.                     break;
  1751.                 }
  1752.             }
  1753.  
  1754.             BytesRead++;
  1755.  
  1756.             if((Buffer[i] = Data[ReadIndex++]) == '\n')
  1757.             {
  1758.                 Buffer[i + 1] = 0;
  1759.  
  1760.                 break;
  1761.             }
  1762.         }
  1763.     }
  1764.     else
  1765.         ReadIndex = ReadLen = 0;
  1766.  
  1767.     return(BytesRead);
  1768. }
  1769.  
  1770.     /* GetBaudRate(STRPTR Buffer):
  1771.      *
  1772.      *    Calculate the baud rate contained in a connect string.
  1773.      */
  1774.  
  1775. LONG
  1776. GetBaudRate(STRPTR Buffer)
  1777. {
  1778.     UBYTE LocalBuffer[40];
  1779.     LONG Rate,i,j;
  1780.  
  1781.     for(i = j = 0 ; i < strlen(Buffer) ; i++)
  1782.     {
  1783.         if(Buffer[i] == ' ')
  1784.             continue;
  1785.         else
  1786.         {
  1787.             if(Buffer[i] >= '0' && Buffer[i] <= '9')
  1788.                 LocalBuffer[j++] = Buffer[i];
  1789.             else
  1790.                 break;
  1791.         }
  1792.     }
  1793.  
  1794.     LocalBuffer[j] = 0;
  1795.  
  1796.     if(StrToLong(LocalBuffer,&Rate) > 0)
  1797.     {
  1798.         if(Rate > 0)
  1799.             return(Rate);
  1800.     }
  1801.  
  1802.     return(0);
  1803. }
  1804.  
  1805.     /* GetFileSize(STRPTR Name):
  1806.      *
  1807.      *    Simple routine to return the size of a file in
  1808.      *    bytes.
  1809.      */
  1810.  
  1811. LONG
  1812. GetFileSize(STRPTR Name)
  1813. {
  1814.     BPTR FileLock;
  1815.     LONG FileSize = 0;
  1816.     D_S(struct FileInfoBlock,FileInfo);
  1817.  
  1818.     if(FileLock = Lock(Name,ACCESS_READ))
  1819.     {
  1820.         if(Examine(FileLock,FileInfo))
  1821.         {
  1822.             if(FileInfo->fib_DirEntryType < 0)
  1823.                 FileSize = FileInfo->fib_Size;
  1824.         }
  1825.  
  1826.         UnLock(FileLock);
  1827.     }
  1828.  
  1829.     return(FileSize);
  1830. }
  1831.  
  1832.     /* PutDimensionTags(struct Window *Reference,LONG Left,LONG Top,LONG Width,LONG Height):
  1833.      *
  1834.      *    Put back the default values for the requesters to open.
  1835.      */
  1836.  
  1837. VOID
  1838. PutDimensionTags(struct Window *Reference,LONG Left,LONG Top,LONG Width,LONG Height)
  1839. {
  1840.     if(Config->MiscConfig->RequesterMode != REQUESTERMODE_IGNORE && (!Config->MiscConfig->RequesterWidth || !Config->MiscConfig->RequesterHeight))
  1841.     {
  1842.         if(!Reference)
  1843.             Reference = Window;
  1844.  
  1845.         Config->MiscConfig->RequesterLeft    = Left    - Reference->LeftEdge;
  1846.         Config->MiscConfig->RequesterTop    = Top    - Reference->TopEdge;
  1847.         Config->MiscConfig->RequesterWidth    = Width;
  1848.         Config->MiscConfig->RequesterHeight    = Height;
  1849.     }
  1850. }
  1851.  
  1852.     /* GetDimensionTags(struct Window *Reference,struct TagItem *Tags):
  1853.      *
  1854.      *    Fills an array of tagitems with the dimensions of an asl requester
  1855.      *    to be opened.
  1856.      */
  1857.  
  1858. struct TagItem *
  1859. GetDimensionTags(struct Window *Reference,struct TagItem *Tags)
  1860. {
  1861.     if(Config->MiscConfig->RequesterMode == REQUESTERMODE_IGNORE || Config->MiscConfig->RequesterWidth < 1 || Config->MiscConfig->RequesterHeight < 1)
  1862.     {
  1863.         STATIC ULONG Done = TAG_DONE;
  1864.  
  1865.         return((struct TagItem *)&Done);
  1866.     }
  1867.     else
  1868.     {
  1869.         LONG Left,Top,Width,Height;
  1870.  
  1871.         if(!Reference)
  1872.             Reference = Window;
  1873.  
  1874.         if(Config->MiscConfig->RequesterMode == REQUESTERMODE_CENTRE)
  1875.         {
  1876.             Left    = Reference->LeftEdge    + (Reference->Width - Config->MiscConfig->RequesterWidth) / 2;
  1877.             Top        = Reference->TopEdge    + (Reference->Height - Config->MiscConfig->RequesterHeight) / 2;
  1878.         }
  1879.         else
  1880.         {
  1881.             Left    = Config->MiscConfig->RequesterLeft    + Reference->LeftEdge;
  1882.             Top        = Config->MiscConfig->RequesterTop    + Reference->TopEdge;
  1883.         }
  1884.  
  1885.         Width    = Config->MiscConfig->RequesterWidth;
  1886.         Height    = Config->MiscConfig->RequesterHeight;
  1887.  
  1888.         Tags[0].ti_Tag    = ASL_LeftEdge;
  1889.         Tags[0].ti_Data    = Left;
  1890.         Tags[1].ti_Tag    = ASL_TopEdge;
  1891.         Tags[1].ti_Data    = Top;
  1892.         Tags[2].ti_Tag    = ASL_Width;
  1893.         Tags[2].ti_Data    = Width;
  1894.         Tags[3].ti_Tag    = ASL_Height;
  1895.         Tags[3].ti_Data    = Height;
  1896.         Tags[4].ti_Tag    = TAG_DONE;
  1897.  
  1898.         return(Tags);
  1899.     }
  1900. }
  1901.  
  1902.     /* ShowRequest(struct Window *Window,STRPTR Text,STRPTR Gadgets,...):
  1903.      *
  1904.      *    Really quite simple varargs version of Intuition's
  1905.      *    EasyRequest requester.
  1906.      */
  1907.  
  1908. LONG
  1909. ShowRequest(struct Window *Window,STRPTR Text,STRPTR Gadgets,...)
  1910. {
  1911.     struct EasyStruct Easy;
  1912.     va_list VarArgs;
  1913.     LONG i,GadgetCount;
  1914.  
  1915.     for(i = GadgetCount = 0 ; i < strlen(Gadgets) ; i++)
  1916.     {
  1917.         if(Gadgets[i] == '|')
  1918.             GadgetCount++;
  1919.     }
  1920.  
  1921.         /* Standard data. */
  1922.  
  1923.     Easy.es_StructSize        = sizeof(struct EasyStruct);
  1924.     Easy.es_Flags            = NULL;
  1925.     Easy.es_Title            = LocaleString(MSG_TERMAUX_TERM_REQUEST_TXT);
  1926.     Easy.es_TextFormat        = Text;
  1927.     Easy.es_GadgetFormat    = Gadgets;
  1928.  
  1929.     if(GadgetCount)
  1930.     {
  1931.         LONG Result;
  1932.  
  1933.         if(GTLayoutBase)
  1934.             LT_LockWindow(Window);
  1935.  
  1936.             /* Use the argument array to build the
  1937.              * requester and display it.
  1938.              */
  1939.  
  1940.         va_start(VarArgs,Gadgets);
  1941.         Result = EasyRequestArgs(Window,&Easy,NULL,(APTR)VarArgs);
  1942.         va_end(VarArgs);
  1943.  
  1944.         if(GTLayoutBase)
  1945.             LT_UnlockWindow(Window);
  1946.  
  1947.         return(Result);
  1948.     }
  1949.     else
  1950.     {
  1951.         struct Window *ReqWindow;
  1952.  
  1953.         if(GTLayoutBase)
  1954.             LT_LockWindow(Window);
  1955.  
  1956.         va_start(VarArgs,Gadgets);
  1957.  
  1958.         if(ReqWindow = BuildEasyRequestArgs(Window,&Easy,IDCMP_RAWKEY,(APTR)VarArgs))
  1959.         {
  1960.             ULONG    IDCMP;
  1961.             LONG    Result;
  1962.  
  1963.             FOREVER
  1964.             {
  1965.                 WaitPort(ReqWindow->UserPort);
  1966.  
  1967.                 IDCMP = NULL;
  1968.  
  1969.                 Result = SysReqHandler(ReqWindow,&IDCMP,FALSE);
  1970.  
  1971.                 if(!Result || (Result == -2 && !(IDCMP & IDCMP_RAWKEY)))
  1972.                     break;
  1973.             }
  1974.  
  1975.             FreeSysRequest(ReqWindow);
  1976.         }
  1977.  
  1978.         va_end(VarArgs);
  1979.  
  1980.         if(GTLayoutBase)
  1981.             LT_UnlockWindow(Window);
  1982.  
  1983.         return(0);
  1984.     }
  1985. }
  1986.  
  1987.     /* CloseWindowSafely(struct Window *Window):
  1988.      *
  1989.      *    Close a window freeing all messages pending at
  1990.      *    its user port (taken from example source code
  1991.      *    published once upon a time in Amiga Mail).
  1992.      */
  1993.  
  1994. VOID
  1995. CloseWindowSafely(struct Window *Window)
  1996. {
  1997.     Forbid();
  1998.  
  1999.     if(Window->UserPort)
  2000.     {
  2001.         struct Node *Node,*Next;
  2002.  
  2003.         for(Node = Window->UserPort->mp_MsgList.lh_Head ; Next = Node->ln_Succ ; Node = Next)
  2004.         {
  2005.             if(((struct IntuiMessage *)Node)->IDCMPWindow == Window)
  2006.             {
  2007.                 Remove(Node);
  2008.                 ReplyMsg((struct Message *)Node);
  2009.             }
  2010.         }
  2011.  
  2012.         Window->UserPort = NULL;
  2013.     }
  2014.  
  2015.     ModifyIDCMP(Window,NULL);
  2016.  
  2017.     Permit();
  2018.  
  2019.     LT_DeleteWindowLock(Window);
  2020.  
  2021.     CloseWindow(Window);
  2022. }
  2023.  
  2024.     /* GetEnvDOS(STRPTR Name,STRPTR Buffer):
  2025.      *
  2026.      *    Get the contents of a vanilla AmigaDOS environment
  2027.      *    variable.
  2028.      */
  2029.  
  2030. BOOL
  2031. GetEnvDOS(STRPTR Name,STRPTR Buffer,LONG BufferSize)
  2032. {
  2033.     if(GetVar(Name,Buffer,256,NULL) >= 0)
  2034.         return(TRUE);
  2035.     else
  2036.     {
  2037.         Buffer[0] = 0;
  2038.  
  2039.         return(FALSE);
  2040.     }
  2041. }
  2042.  
  2043.     /* SetEnvDOS(STRPTR Name,STRPTR Value):
  2044.      *
  2045.      *    Set the contents of a vanilla AmigaDOS environment
  2046.      *    variable.
  2047.      */
  2048.  
  2049. BOOL
  2050. SetEnvDOS(STRPTR Name,STRPTR Value)
  2051. {
  2052.     if(SetVar(Name,Value,-1,GVF_SAVE_VAR))
  2053.     {
  2054.             /* Ouch! Bug in dos.library V39! GVF_SAVE_VAR doesn't
  2055.              * work unless GVF_GLOBAL_ONLY is set as well.
  2056.              */
  2057.  
  2058. /*        if(Kick30)*/
  2059. /*            return(TRUE);*/
  2060. /*        else*/
  2061.         {
  2062.             UBYTE LocalBuffer[MAX_FILENAME_LENGTH];
  2063.             BOOL Result = FALSE;
  2064.  
  2065.             strcpy(LocalBuffer,"ENVARC:");
  2066.  
  2067.             if(AddPart(LocalBuffer,FilePart(Name),sizeof(LocalBuffer)))
  2068.             {
  2069.                 BPTR FileHandle;
  2070.  
  2071.                 if(!(FileHandle = Open(LocalBuffer,MODE_NEWFILE)))
  2072.                     Result = FALSE;
  2073.                 else
  2074.                 {
  2075.                     LONG Length = strlen(Value);
  2076.  
  2077.                     if(Write(FileHandle,Value,Length) == Length)
  2078.                         Result = TRUE;
  2079.  
  2080.                     Close(FileHandle);
  2081.                 }
  2082.             }
  2083.  
  2084.             return(Result);
  2085.         }
  2086.     }
  2087.  
  2088.     return(FALSE);
  2089. }
  2090.  
  2091.     /* BumpWindow(struct Window *SomeWindow):
  2092.      *
  2093.      *    Bring a window to the front (and shift the screen
  2094.      *    back to its initial position).
  2095.      */
  2096.  
  2097. VOID
  2098. BumpWindow(struct Window *SomeWindow)
  2099. {
  2100.     if(SomeWindow)
  2101.     {
  2102.         if(SomeWindow->WScreen->LeftEdge > 0)
  2103.         {
  2104.             if(SomeWindow->WScreen->TopEdge > 0)
  2105.                 MoveScreen(SomeWindow->WScreen,-SomeWindow->WScreen->LeftEdge,-SomeWindow->WScreen->TopEdge);
  2106.             else
  2107.                 MoveScreen(SomeWindow->WScreen,-SomeWindow->WScreen->LeftEdge,0);
  2108.         }
  2109.         else
  2110.         {
  2111.             if(SomeWindow->WScreen->TopEdge > 0)
  2112.                 MoveScreen(SomeWindow->WScreen,0,-SomeWindow->WScreen->TopEdge);
  2113.         }
  2114.  
  2115.         ScreenToFront(SomeWindow->WScreen);
  2116.  
  2117.         ActivateWindow(SomeWindow);
  2118.     }
  2119. }
  2120.  
  2121.     /* PushWindow(struct Window *Window):
  2122.      *
  2123.      *    Push/PopWindow implement a single lifo window stack
  2124.      *    which always updates the window to activate when
  2125.      *    LSHIFT+RSHIFT+RETURN is pressed. This routine will
  2126.      *    push a window on the stack.
  2127.      */
  2128.  
  2129. VOID
  2130. PushWindow(struct Window *Window)
  2131. {
  2132.     if(WindowStackPtr < 5)
  2133.     {
  2134.         WindowStack[WindowStackPtr++] = Window;
  2135.  
  2136.         TopWindow = Window;
  2137.     }
  2138. }
  2139.  
  2140.     /* PopWindow():
  2141.      *
  2142.      *    Remove topmost window from window stack.
  2143.      */
  2144.  
  2145. VOID
  2146. PopWindow()
  2147. {
  2148.     if(WindowStackPtr > 0)
  2149.     {
  2150.         WindowStackPtr--;
  2151.  
  2152.         if(WindowStackPtr)
  2153.             TopWindow = WindowStack[WindowStackPtr - 1];
  2154.         else
  2155.             TopWindow = Window;
  2156.     }
  2157. }
  2158.  
  2159.     /* SplitFileName():
  2160.      *
  2161.      *    Split a full file name into a file and a drawer name.
  2162.      */
  2163.  
  2164. VOID
  2165. SplitFileName(STRPTR FullName,STRPTR *FileName,STRPTR DrawerName)
  2166. {
  2167.     if(FilePart(FullName) == FullName)
  2168.     {
  2169.         *DrawerName    = 0;
  2170.         *FileName    = FullName;
  2171.     }
  2172.     else
  2173.     {
  2174.         STRPTR Dummy;
  2175.  
  2176.         strcpy(DrawerName,FullName);
  2177.  
  2178.         Dummy = PathPart(DrawerName);
  2179.  
  2180.         *Dummy = 0;
  2181.  
  2182.         *FileName = FilePart(FullName);
  2183.     }
  2184. }
  2185.  
  2186.     /* BackfillRoutine():
  2187.      *
  2188.      *    Window layer backfill routine.
  2189.      */
  2190.  
  2191. VOID SAVE_DS ASM
  2192. BackfillRoutine(REG(a0) struct Hook *UnusedHook,REG(a2) struct RastPort *RPort,REG(a1) LayerMsg *Bounds)
  2193. {
  2194.     struct RastPort RastPort;
  2195.  
  2196.     CopyMem(RPort,&RastPort,sizeof(struct RastPort));
  2197.     RastPort.Layer = NULL;
  2198.  
  2199.     RPort = &RastPort;
  2200.  
  2201.     SetAPen(RPort,Pens[BACKGROUNDPEN]);
  2202.     SetDrMd(RPort,JAM2);
  2203.  
  2204.     RectFill(RPort,Bounds->Bounds.MinX,Bounds->Bounds.MinY,Bounds->Bounds.MaxX,Bounds->Bounds.MaxY);
  2205. }
  2206.  
  2207. struct NameSegment
  2208. {
  2209.     UBYTE    String[63],
  2210.             Separator;
  2211. };
  2212.  
  2213. STATIC STRPTR
  2214. FindChar(STRPTR Template,LONG c)
  2215. {
  2216.     while(*Template)
  2217.     {
  2218.         if(*Template == c)
  2219.             return(Template);
  2220.         else
  2221.             Template++;
  2222.     }
  2223.  
  2224.     return(NULL);
  2225. }
  2226.  
  2227. STATIC UBYTE *
  2228. GetNameSegment(struct NameSegment *NameSegment,UBYTE *cp,LONG i)
  2229. {
  2230.     UBYTE *xp = NameSegment[i].String;
  2231.  
  2232.     while (*cp && !FindChar("._+-,@~=",*cp))
  2233.         *xp++ = *cp++;
  2234.  
  2235.     *xp = '\0';
  2236.  
  2237.     NameSegment[i].Separator = *cp;
  2238.  
  2239.     if (*cp)
  2240.         cp++;
  2241.  
  2242.     if(NameSegment[i].String[0] || NameSegment[i].Separator)
  2243.         return(cp);
  2244.     else
  2245.         return(NULL);
  2246. }
  2247.  
  2248. STATIC VOID
  2249. CopyNameSegment(struct NameSegment *NameSegment,UBYTE *Destination,LONG Zap)
  2250. {
  2251.     UBYTE *cp = Destination,*xp;
  2252.  
  2253.     for(xp = NameSegment[0].String ; *xp ; )
  2254.         *cp++ = *xp++;
  2255.  
  2256.     if(NameSegment[0].Separator)
  2257.     {
  2258.         LONG i;
  2259.  
  2260.         *cp++ = NameSegment[0].Separator;
  2261.  
  2262.         for(i = Zap + 1 ; ; i++)
  2263.         {
  2264.             for(xp = NameSegment[i].String ; *xp ; )
  2265.                 *cp++ = *xp++;
  2266.  
  2267.             if(NameSegment[i].Separator)
  2268.                 *cp++ = NameSegment[i].Separator;
  2269.             else
  2270.             {
  2271.                 if(!NameSegment[i].String[0])
  2272.                     break;
  2273.             }
  2274.         }
  2275.     }
  2276.  
  2277.     *cp = 0;
  2278. }
  2279.  
  2280.     /* ShrinkName():
  2281.      *
  2282.      *    Shrink a file name down to a number of characters, if
  2283.      *    possible preserving the structure of the name. Algorithm
  2284.      *    courtesy of the "shrink" program by Simon Brown,
  2285.      *    Edinburgh University.
  2286.      */
  2287.  
  2288. UBYTE *
  2289. ShrinkName(UBYTE *Source,UBYTE *Destination,LONG MaxLength,BOOL FixSuffix)
  2290. {
  2291.     #define MAXSEGS 10
  2292.  
  2293.     struct NameSegment NameSegment[MAXSEGS];
  2294.  
  2295.     LONG i,NumSegments,SuffixLength,Remainder,Delete,Total,Zap = 0;
  2296.     UBYTE *OldPtr = (UBYTE *)Source;
  2297.  
  2298.     for(i = 0 ; i < MAXSEGS && (OldPtr = GetNameSegment(NameSegment,OldPtr,i)) ; i++);
  2299.  
  2300.     if(i < MAXSEGS)
  2301.     {
  2302.         NumSegments = i - 1;
  2303.  
  2304.         if((NumSegments * 2) < MaxLength)
  2305.         {
  2306.             SuffixLength = strlen(NameSegment[NumSegments].String);
  2307.  
  2308.             if(SuffixLength > MaxLength - NumSegments - 1)
  2309.             {
  2310.                 SuffixLength = MaxLength - (2 * NumSegments) - 1;
  2311.  
  2312.                 NameSegment[NumSegments].String[SuffixLength - 1] = 0;
  2313.             }
  2314.             else
  2315.             {
  2316.                 if (SuffixLength + NumSegments > MaxLength-NumSegments-1)
  2317.                     Zap = NumSegments - (MaxLength-SuffixLength)/2;
  2318.             }
  2319.  
  2320.             if(NumSegments >= 1)
  2321.             {
  2322.                 for(i = Zap + 1 ; i <= NumSegments ; i++)
  2323.                 {
  2324.                     if(NameSegment[i].Separator)
  2325.                         SuffixLength++;
  2326.                 }
  2327.  
  2328.                 if(NameSegment[0].Separator)
  2329.                     SuffixLength++;
  2330.  
  2331.                 Remainder = MaxLength - SuffixLength;
  2332.  
  2333.                 Delete = Remainder / NumSegments;
  2334.  
  2335.                 Total = SuffixLength;
  2336.  
  2337.                 for(i = Zap + 1 ; i < NumSegments ; i++)
  2338.                 {
  2339.                     NameSegment[i].String[Delete] = 0;
  2340.  
  2341.                     Total += Delete;
  2342.                 }
  2343.  
  2344.                 NameSegment[0].String[MaxLength - Total] = 0;
  2345.             }
  2346.  
  2347.             CopyNameSegment(NameSegment,Destination,Zap);
  2348.         }
  2349.         else
  2350.             strcpy(Destination,Source);
  2351.     }
  2352.     else
  2353.         strcpy(Destination,Source);
  2354.  
  2355.     if(FixSuffix)
  2356.     {
  2357.         BOOL    GotDot    = FALSE;
  2358.         LONG    Len    = strlen(Destination),Dots;
  2359.  
  2360.         for(i = Dots = 0 ; i < Len ; i++)
  2361.         {
  2362.             if(Destination[i] == '.')
  2363.                 Dots++;
  2364.         }
  2365.  
  2366.         if(!Dots)
  2367.         {
  2368.             if(Len < 4)
  2369.                 strcat(Destination,".___");
  2370.             else
  2371.                 Destination[Len - 4] = '.';
  2372.         }
  2373.  
  2374.         for(i = Len - 1 ; i >= 0 ; i--)
  2375.         {
  2376.             if(Destination[i] == '.')
  2377.             {
  2378.                 if(GotDot)
  2379.                     Destination[i] = '_';
  2380.                 else
  2381.                     GotDot = TRUE;
  2382.             }
  2383.  
  2384.             if(Destination[i] == '\\')
  2385.                 Destination[i] = '-';
  2386.         }
  2387.     }
  2388.  
  2389.     return(Destination);
  2390. }
  2391.  
  2392.     /* BuildFontName(STRPTR Destination,STRPTR Name,LONG Size):
  2393.      *
  2394.      *    Build a font name and size string from given
  2395.      *    information (raw name and size).
  2396.      */
  2397.  
  2398. VOID
  2399. BuildFontName(STRPTR Destination,LONG DestinationSize,STRPTR Name,LONG Size)
  2400. {
  2401.     UBYTE LocalBuffer[MAX_FILENAME_LENGTH];
  2402.     LONG Len;
  2403.  
  2404.     Name    = FilePart(Name);
  2405.     Len        = strlen(Name);
  2406.  
  2407.     if(Len > 5 && !Stricmp(&Name[Len - 5],".font"))
  2408.     {
  2409.         strcpy(LocalBuffer,Name);
  2410.  
  2411.         LocalBuffer[Len - 5] = 0;
  2412.  
  2413.         Name = LocalBuffer;
  2414.     }
  2415.  
  2416.     LimitedSPrintf(DestinationSize,Destination,"%s %ld",Name,Size);
  2417. }
  2418.  
  2419.     /* FixName(STRPTR Name):
  2420.      *
  2421.      *    Build a correct AmigaDOS filename.
  2422.      */
  2423.  
  2424. VOID
  2425. FixName(STRPTR Name)
  2426. {
  2427.     LONG NameLen = strlen(Name),i;
  2428.  
  2429.         /* Replace special characters. */
  2430.  
  2431.     for(i = 0 ; i < NameLen ; i++)
  2432.     {
  2433.         switch(Name[i])
  2434.         {
  2435.             case ' ':
  2436.  
  2437.                 Name[i] = '_';
  2438.                 break;
  2439.  
  2440.             case ':':
  2441.  
  2442.                 Name[i] = '.';
  2443.                 break;
  2444.  
  2445.             case '/':
  2446.  
  2447.                 Name[i] = '\\';
  2448.                 break;
  2449.  
  2450.             case '\"':
  2451.  
  2452.                 Name[i] = '\'';
  2453.                 break;
  2454.         }
  2455.     }
  2456.  
  2457.         /* Truncate the name. */
  2458.  
  2459.     if(NameLen > 31)
  2460.         Name[31] = 0;
  2461. }
  2462.  
  2463.     /* ShowError(struct Window *Window,LONG Primary,LONG Secondary,STRPTR String):
  2464.      *
  2465.      *    Display an error message, in human readable form if possible.
  2466.      */
  2467.  
  2468. VOID
  2469. ShowError(struct Window *Window,LONG Primary,LONG Secondary,STRPTR String)
  2470. {
  2471.     STATIC LONG LocalErrors[][2] =
  2472.     {
  2473.         ERR_SAVE_ERROR,            MSG_ERR_COULD_NOT_SAVE_FILE_TXT,
  2474.         ERR_LOAD_ERROR,            MSG_ERR_COULD_NOT_LOAD_FILE_TXT,
  2475.         ERR_OUTDATED,            MSG_ERR_OUTDATED_TXT,
  2476.         ERR_EXECUTE_ERROR,        MSG_ERR_COULD_NOT_EXECUTE_PROGRAM_TXT,
  2477.  
  2478.         ERR_FILE_NOT_FOUND,        MSG_VERIFY_NO_FILE_TXT,
  2479.         ERR_DRAWER_NOT_FOUND,    MSG_VERIFY_DRAWER_NOT_FOUND_TXT,
  2480.         ERR_PROGRAM_NOT_FOUND,    MSG_VERIFY_NO_PROGRAM_TXT,
  2481.         ERR_NOT_A_FILE,            MSG_VERIFY_DRAWER_NOT_A_FILE_TXT,
  2482.         ERR_NOT_A_DRAWER,        MSG_VERIFY_FILE_NOT_A_DRAWER_TXT,
  2483.  
  2484.         IFFERR_NOMEM,            MSG_IFFERR_NOMEM_TXT,
  2485.         IFFERR_READ,            MSG_IFFERR_READ_TXT,
  2486.         IFFERR_WRITE,            MSG_IFFERR_WRITE_TXT,
  2487.         IFFERR_SEEK,            MSG_IFFERR_SEEK_TXT,
  2488.         IFFERR_MANGLED,            MSG_IFFERR_MANGLED_TXT,
  2489.         IFFERR_NOTIFF,            MSG_IFFERR_NOTIFF_TXT,
  2490.  
  2491.         0
  2492.     };
  2493.  
  2494.     UBYTE LocalBuffer1[FAULT_MAX],LocalBuffer2[FAULT_MAX];
  2495.     STRPTR PrimaryError,SecondaryError;
  2496.  
  2497.     PrimaryError = SecondaryError = NULL;
  2498.  
  2499.     if(Primary)
  2500.     {
  2501.         LONG i;
  2502.  
  2503.         for(i = 0 ; LocalErrors[i][0] ; i++)
  2504.         {
  2505.             if(LocalErrors[i][0] == Primary)
  2506.             {
  2507.                 PrimaryError = LocaleString(LocalErrors[i][1]);
  2508.  
  2509.                 break;
  2510.             }
  2511.         }
  2512.  
  2513.         if(!PrimaryError)
  2514.         {
  2515.             if(Fault(Primary,NULL,LocalBuffer1,sizeof(LocalBuffer1)))
  2516.                 PrimaryError = LocalBuffer1;
  2517.         }
  2518.     }
  2519.  
  2520.     if(Secondary)
  2521.     {
  2522.         LONG i;
  2523.  
  2524.         for(i = 0 ; LocalErrors[i][0] ; i++)
  2525.         {
  2526.             if(LocalErrors[i][0] == Secondary)
  2527.             {
  2528.                 SecondaryError = LocaleString(LocalErrors[i][1]);
  2529.  
  2530.                 break;
  2531.             }
  2532.         }
  2533.  
  2534.         if(!SecondaryError)
  2535.         {
  2536.             if(Fault(Secondary,NULL,LocalBuffer2,sizeof(LocalBuffer2)))
  2537.                 SecondaryError = LocalBuffer2;
  2538.         }
  2539.     }
  2540.  
  2541.     if(PrimaryError)
  2542.     {
  2543.         if(String)
  2544.             ShowRequest(Window,PrimaryError,LocaleString(MSG_GLOBAL_CONTINUE_TXT),String,SecondaryError);
  2545.         else
  2546.             ShowRequest(Window,PrimaryError,LocaleString(MSG_GLOBAL_CONTINUE_TXT),SecondaryError);
  2547.     }
  2548. }
  2549.  
  2550. struct List *
  2551. BuildModeList(LONG *Index,ULONG DisplayMode,MODEFILTER ModeFilter,APTR UserData)
  2552. {
  2553.     struct List    *List;
  2554.     LONG         Count = 0;
  2555.  
  2556.     *Index = 0;
  2557.  
  2558.     if(List = CreateList())
  2559.     {
  2560.         struct DisplayInfo    DisplayInfo;
  2561.         ULONG                SomeMode = INVALID_ID;
  2562.  
  2563.         while((SomeMode = NextDisplayInfo(SomeMode)) != INVALID_ID)
  2564.         {
  2565.             if(GetDisplayInfoData(NULL,(APTR)&DisplayInfo,sizeof(struct DisplayInfo),DTAG_DISP,SomeMode))
  2566.             {
  2567.                 if((DisplayInfo.PropertyFlags & DIPF_IS_WB) && !(DisplayInfo.NotAvailable & ~DI_AVAIL_NOTWITHGENLOCK))
  2568.                 {
  2569.                     UBYTE ModeNameBuffer[DISPLAYNAMELEN + 1];
  2570.                     struct ModeNode    *ModeNode;
  2571.  
  2572.                     if(ModeFilter)
  2573.                     {
  2574.                         if(!(*ModeFilter)(SomeMode,UserData))
  2575.                             continue;
  2576.                     }
  2577.  
  2578.                     GetModeName(SomeMode,ModeNameBuffer,sizeof(ModeNameBuffer));
  2579.  
  2580.                     if(ModeNode = (struct ModeNode *)AllocVecPooled(sizeof(struct ModeNode) + strlen(ModeNameBuffer) + 1,MEMF_ANY))
  2581.                     {
  2582.                         strcpy(ModeNode->Node.ln_Name = (STRPTR)(ModeNode + 1),ModeNameBuffer);
  2583.  
  2584.                         ModeNode->DisplayID = SomeMode;
  2585.  
  2586.                         AddTail(List,(struct Node *)ModeNode);
  2587.  
  2588.                         Count++;
  2589.                     }
  2590.                 }
  2591.             }
  2592.         }
  2593.     }
  2594.  
  2595.     if(Count)
  2596.     {
  2597.         struct ModeNode    *Node,*Next;
  2598.  
  2599.         for(Node = (struct ModeNode *)List->lh_Head ; Node->Node.ln_Succ ; Node = (struct ModeNode *)Node->Node.ln_Succ)
  2600.         {
  2601.             if(!(Node->DisplayID & MONITOR_ID_MASK))
  2602.             {
  2603.                 for(Next = (struct ModeNode *)List->lh_Head ; Next->Node.ln_Succ ; Next = (struct ModeNode *)Next->Node.ln_Succ)
  2604.                 {
  2605.                     if((Node->DisplayID & ~MONITOR_ID_MASK) == (Next->DisplayID & ~MONITOR_ID_MASK) && Next != Node)
  2606.                         Node->DisplayID = INVALID_ID;
  2607.                 }
  2608.             }
  2609.  
  2610.             for(Next = (struct ModeNode *)List->lh_Head ; Next->Node.ln_Succ ; Next = (struct ModeNode *)Next->Node.ln_Succ)
  2611.             {
  2612.                 if(Node->DisplayID == Next->DisplayID && Next != Node)
  2613.                     Next->DisplayID = INVALID_ID;
  2614.             }
  2615.         }
  2616.  
  2617.         for(Node = (struct ModeNode *)List->lh_Head ; Next = (struct ModeNode *)Node->Node.ln_Succ ; Node = Next)
  2618.         {
  2619.             if(Node->DisplayID == INVALID_ID)
  2620.             {
  2621.                 Count--;
  2622.  
  2623.                 Remove((struct Node *)Node);
  2624.  
  2625.                 FreeVecPooled(Node);
  2626.             }
  2627.         }
  2628.     }
  2629.  
  2630.     if(Count)
  2631.     {
  2632.         struct ModeNode    *Node,*Next;
  2633.  
  2634.         for(Count = 0, Node = (struct ModeNode *)List->lh_Head ; Next = (struct ModeNode *)Node->Node.ln_Succ ; Node = Next)
  2635.         {
  2636.             if(Node->DisplayID == DisplayMode)
  2637.             {
  2638.                 *Index = Count;
  2639.  
  2640.                 break;
  2641.             }
  2642.         }
  2643.  
  2644.         return(List);
  2645.     }
  2646.     else
  2647.     {
  2648.         DeleteList(List);
  2649.  
  2650.         return(NULL);
  2651.     }
  2652. }
  2653.  
  2654.     /* IsAssign(STRPTR Name):
  2655.      *
  2656.      *    Does a name refer to an assignment?
  2657.      */
  2658.  
  2659. BOOL
  2660. IsAssign(STRPTR Name)
  2661. {
  2662.     LONG NameLen    = strlen(Name) - 1;
  2663.     BOOL Result        = FALSE;
  2664.  
  2665.         /* Does it end with a colon? */
  2666.  
  2667.     if(Name[NameLen] == ':')
  2668.     {
  2669.         struct DosList *DosList;
  2670.         STRPTR AssignName;
  2671.  
  2672.             /* Lock the list of assignments for reading. */
  2673.  
  2674.         DosList = LockDosList(LDF_ASSIGNS | LDF_READ);
  2675.  
  2676.             /* Scan the list... */
  2677.  
  2678.         while(DosList = NextDosEntry(DosList,LDF_ASSIGNS))
  2679.         {
  2680.                 /* Convert the name from icky
  2681.                  * BCPL to `C' style string.
  2682.                  */
  2683.  
  2684.             AssignName = (STRPTR)BADDR(DosList->dol_Name);
  2685.  
  2686.                 /* Does the name length match? */
  2687.  
  2688.             if(AssignName[0] == NameLen)
  2689.             {
  2690.                     /* Does the name itself match? */
  2691.  
  2692.                 if(!Strnicmp(&AssignName[1],Name,NameLen))
  2693.                 {
  2694.                     Result = TRUE;
  2695.  
  2696.                     break;
  2697.                 }
  2698.             }
  2699.         }
  2700.  
  2701.             /* Unlock the list of assignments. */
  2702.  
  2703.         UnLockDosList(LDF_ASSIGNS | LDF_READ);
  2704.     }
  2705.  
  2706.         /* Return the result. */
  2707.  
  2708.     return(Result);
  2709. }
  2710.  
  2711.     /* LockInAssign(BPTR TheLock,STRPTR TheAssignment):
  2712.      *
  2713.      *    Check if a file lock is part of an assignment.
  2714.      */
  2715.  
  2716. BOOL
  2717. LockInAssign(BPTR TheLock,STRPTR TheAssignment)
  2718. {
  2719.     struct DevProc    *DevProc        = NULL;
  2720.     struct MsgPort    *FileSysTask    = GetFileSysTask();
  2721.     BOOL             Result            = FALSE;
  2722.  
  2723.  
  2724.         /* Loop until all assignments are
  2725.          * processed.
  2726.          */
  2727.  
  2728.     do
  2729.     {
  2730.             /* Get the default filesystem task
  2731.              * in case we stumble upon NULL
  2732.              * directory locks.
  2733.              */
  2734.  
  2735.         if(DevProc = GetDeviceProc(TheAssignment,DevProc))
  2736.         {
  2737.                 /* Set the default filesystem task. */
  2738.  
  2739.             SetFileSysTask(DevProc->dvp_Port);
  2740.  
  2741.                 /* Is the lock on the list? */
  2742.  
  2743.             if(SameLock(DevProc->dvp_Lock,TheLock) == LOCK_SAME)
  2744.                 Result = TRUE;
  2745.         }
  2746.         else
  2747.             break;
  2748.     }
  2749.     while(DevProc && (DevProc->dvp_Flags & DVPF_ASSIGN) && !Result);
  2750.  
  2751.         /* Reset the default filesystem task. */
  2752.  
  2753.     SetFileSysTask(FileSysTask);
  2754.  
  2755.         /* Free device process data. */
  2756.  
  2757.     if(DevProc)
  2758.         FreeDeviceProc(DevProc);
  2759.  
  2760.     return(Result);
  2761. }
  2762.  
  2763.     /* DeleteBitMap(struct BitMap *BitMap):
  2764.      *
  2765.      *    Delete a bitmap created by CreateBitMap().
  2766.      */
  2767.  
  2768. VOID
  2769. DeleteBitMap(struct BitMap *BitMap)
  2770. {
  2771.     if(BitMap)
  2772.     {
  2773.         WaitBlit();
  2774.  
  2775.         if(Kick30)
  2776.             FreeBitMap(BitMap);
  2777.         else
  2778.         {
  2779.             LONG i,*Sizes,Width,Height;
  2780.  
  2781.             Sizes = &((LONG *)BitMap)[-2];
  2782.  
  2783.             Width = Sizes[0];
  2784.             Height = Sizes[1];
  2785.  
  2786.             for(i = 0 ; i < BitMap->Depth ; i++)
  2787.                 FreeRaster(BitMap->Planes[i],Width,Height);
  2788.  
  2789.             FreeVecPooled(Sizes);
  2790.         }
  2791.     }
  2792. }
  2793.  
  2794.     /* CreateBitMap(ULONG Width,ULONG Height,ULONG Depth,ULONG Flags,struct BitMap *Friend):
  2795.      *
  2796.      *    Create a new bitmap with given properties.
  2797.      */
  2798.  
  2799. struct BitMap *
  2800. CreateBitMap(ULONG Width,ULONG Height,ULONG Depth,ULONG Flags,struct BitMap *Friend)
  2801. {
  2802.     if(Kick30)
  2803.         return(AllocBitMap(Width,Height,Depth,Flags,Friend));
  2804.     else
  2805.     {
  2806.         struct BitMap    *BitMap;
  2807.         LONG             Plus;
  2808.         LONG            *Sizes;
  2809.  
  2810.         if(Depth > 8)
  2811.             Plus = (Depth - 8) * sizeof(PLANEPTR);
  2812.         else
  2813.             Plus = 0;
  2814.  
  2815.         if(!(Sizes = (LONG *)AllocVecPooled(sizeof(LONG) * 2 + sizeof(struct BitMap) + Plus,MEMF_CLEAR)))
  2816.             BitMap = NULL;
  2817.         else
  2818.         {
  2819.             LONG i;
  2820.  
  2821.             BitMap = (struct BitMap *)&Sizes[2];
  2822.  
  2823.             InitBitMap(BitMap,Depth,Width,Height);
  2824.  
  2825.             for(i = 0 ; i < BitMap->Depth ; i++)
  2826.             {
  2827.                 if(!(BitMap->Planes[i] = AllocRaster(Width,Height)))
  2828.                 {
  2829.                     LONG j;
  2830.  
  2831.                     for(j = 0 ; j < i ; j++)
  2832.                         FreeRaster(BitMap->Planes[j],Width,Height);
  2833.  
  2834.                     FreeVecPooled(Sizes);
  2835.  
  2836.                     return(NULL);
  2837.                 }
  2838.             }
  2839.  
  2840.             if(Flags & BMF_CLEAR)
  2841.                 BltBitMap(BitMap,0,0,BitMap,0,0,Width,Height,0x00,(1 << Depth) - 1,NULL);
  2842.  
  2843.             Sizes[0] = Width;
  2844.             Sizes[1] = Height;
  2845.         }
  2846.  
  2847.         return(BitMap);
  2848.     }
  2849. }
  2850.  
  2851.     /* LaunchWorkCommon(LaunchMsg *Startup,BOOL Synchronous):
  2852.      *
  2853.      *    Does the final launch & cleanup work with the
  2854.      *    startup packed provided.
  2855.      */
  2856.  
  2857. STATIC BOOL
  2858. LaunchWorkCommon(LaunchMsg *Startup,BOOL Synchronous)
  2859. {
  2860.         /* Did we succeed in creating the startup message? */
  2861.  
  2862.     if(Startup)
  2863.     {
  2864.         LONG Result;
  2865.  
  2866.             /* Launch the program. */
  2867.  
  2868.         Result = LaunchSomething(Config->MiscConfig->SuppressOutput ? (STRPTR)"NIL:" : Config->MiscConfig->WindowName,Synchronous,Startup);
  2869.  
  2870.             /* And return the result. */
  2871.  
  2872.         return((BOOL)(Result == 0));
  2873.     }
  2874.     else
  2875.         return(FALSE);
  2876. }
  2877.  
  2878.     /* RexxLaunchCleanup(LaunchMsg *Startup):
  2879.      *
  2880.      *    Displays an error message for the ARexx script
  2881.      *    to be launched.
  2882.      */
  2883.  
  2884. STATIC VOID
  2885. LaunchRexxCleanup(LaunchMsg *Startup)
  2886. {
  2887.     if(Startup->Result != 0)
  2888.         Printf(LocaleString(MSG_TERMAUX_COMMAND_HAS_TERMINATED_TXT),Startup->Command,Startup->Result,Startup->Result2);
  2889. }
  2890.  
  2891.     /* LaunchRexxCommon(STRPTR Command):
  2892.      *
  2893.      *    Launch an ARexx command. This routine is always
  2894.      *    asynchronous.
  2895.      */
  2896.  
  2897. BOOL
  2898. LaunchRexxAsync(STRPTR Command)
  2899. {
  2900.     LaunchMsg *Startup;
  2901.  
  2902.         /* Skip leading blanks. */
  2903.  
  2904.     while(*Command == ' ' || *Command == '\t')
  2905.         Command++;
  2906.  
  2907.         /* Create the launch startup message. This will copy the
  2908.          * command string.
  2909.          */
  2910.  
  2911.     Startup = CreateRexxCmdLaunchMsg(Command,NULL,LaunchRexxCleanup);
  2912.  
  2913.         /* Do the work. */
  2914.  
  2915.     return((BOOL)(LaunchWorkCommon(Startup,FALSE)));
  2916. }
  2917.  
  2918.     /* LaunchCommandCommon(STRPTR Command, BOOL Synchronous):
  2919.      *
  2920.      *    Launch a command, try to figure out if it's an ARexx
  2921.      *    command, a plain batch file or a program and act
  2922.      *    accordingly.
  2923.      */
  2924.  
  2925. STATIC BOOL
  2926. LaunchCommandCommon(STRPTR Command, BOOL Synchronous)
  2927. {
  2928.     STRPTR         OriginalCommand;
  2929.     UBYTE         NameBuffer[MAX_FILENAME_LENGTH];
  2930.     BOOL         IsScript;
  2931.     BPTR         CommandFile;
  2932.     BPTR         FileLock;
  2933.     LONG         i;
  2934.     LaunchMsg    *Startup;
  2935.  
  2936.         /* Chop off the arguments. */
  2937.  
  2938.     while(*Command == ' ' || *Command == '\t')
  2939.         Command++;
  2940.  
  2941.     OriginalCommand = Command;
  2942.  
  2943.     CopyMem(Command,NameBuffer,sizeof(NameBuffer) - 1);
  2944.  
  2945.     NameBuffer[sizeof(NameBuffer) - 1] = 0;
  2946.  
  2947.     for(i = 0 ; i < sizeof(NameBuffer) ; i++)
  2948.     {
  2949.         if(NameBuffer[i] == ' ' || NameBuffer[i] == '\t')
  2950.         {
  2951.             NameBuffer[i] = 0;
  2952.             break;
  2953.         }
  2954.     }
  2955.  
  2956.         /* Now do something useful. Check if the command
  2957.          * could be an ARexx script.
  2958.          */
  2959.  
  2960.     if(CommandFile = Open(NameBuffer,MODE_OLDFILE))
  2961.     {
  2962.         UBYTE LocalBuffer[MAX_FILENAME_LENGTH];
  2963.         BOOL IsRexx = FALSE;
  2964.         LONG Len;
  2965.  
  2966.             /* 256 bytes may be not be enough, but then
  2967.              * we're only guessing.
  2968.              */
  2969.  
  2970.         if((Len = Read(CommandFile,LocalBuffer,sizeof(LocalBuffer))) > 0)
  2971.         {
  2972.             UBYTE c;
  2973.  
  2974.             for(i = 0 ; i < Len - 1 ; i++)
  2975.             {
  2976.                 c = LocalBuffer[i];
  2977.  
  2978.                     /* Stop on invalid characters. */
  2979.  
  2980.                 if((c < ' ' && c != '\r' && c != '\n' && c != '\a') || (c >= 127 && c < 160))
  2981.                     break;
  2982.                 else
  2983.                 {
  2984.                         /* Looks like the typical
  2985.                          * introductory comment line.
  2986.                          */
  2987.  
  2988.                     if(c == '/' && LocalBuffer[i + 1] == '*')
  2989.                     {
  2990.                         IsRexx = TRUE;
  2991.                         break;
  2992.                     }
  2993.                 }
  2994.             }
  2995.         }
  2996.  
  2997.         Close(CommandFile);
  2998.  
  2999.             /* If it's a Rexx script, launch it. */
  3000.  
  3001.         if(IsRexx)
  3002.             return(LaunchRexxAsync(Command));
  3003.     }
  3004.  
  3005.         /* Ok, second check. Does it have the script bit set? */
  3006.  
  3007.     IsScript = FALSE;
  3008.  
  3009.     if(FileLock = Lock(NameBuffer,ACCESS_READ))
  3010.     {
  3011.         D_S(struct FileInfoBlock,FileInfo);
  3012.  
  3013.         if(Examine(FileLock,FileInfo))
  3014.         {
  3015.             if(FileInfo->fib_Protection & FIBF_SCRIPT)
  3016.                 IsScript = TRUE;
  3017.         }
  3018.  
  3019.         UnLock(FileLock);
  3020.     }
  3021.  
  3022.         /* If it's a script command, prepend the "Execute " command. */
  3023.  
  3024.     if(IsScript)
  3025.     {
  3026.             /* Make room for the new command. */
  3027.  
  3028.         if(!(Command = AllocVecPooled(strlen("Execute ") + strlen(OriginalCommand) + 1,MEMF_ANY)))
  3029.             return(FALSE);
  3030.         else
  3031.         {
  3032.             strcpy(Command,"Execute ");
  3033.             strcat(Command,OriginalCommand);
  3034.         }
  3035.     }
  3036.  
  3037.         /* Create the launch startup message. This will copy the
  3038.          * command string.
  3039.          */
  3040.  
  3041.     Startup = CreateProgramLaunchMsg(Command,NULL);
  3042.  
  3043.         /* If we had to make a copy of the command name, release the memory. */
  3044.  
  3045.     if(Command != OriginalCommand)
  3046.         FreeVecPooled(Command);
  3047.  
  3048.         /* Do the work. */
  3049.  
  3050.     return((BOOL)(LaunchWorkCommon(Startup,Synchronous)));
  3051. }
  3052.  
  3053.     /* LaunchCommand(STRPTR Command):
  3054.      *
  3055.      *    Launches a command, synchronous version.
  3056.      */
  3057.  
  3058. BOOL
  3059. LaunchCommand(STRPTR Command)
  3060. {
  3061.     return(LaunchCommandCommon(Command,TRUE));
  3062. }
  3063.  
  3064.     /* LaunchCommandAsync(STRPTR Command):
  3065.      *
  3066.      *    Launches a command, asynchronous version.
  3067.      */
  3068.  
  3069. BOOL
  3070. LaunchCommandAsync(STRPTR Command)
  3071. {
  3072.     return(LaunchCommandCommon(Command,FALSE));
  3073. }
  3074.  
  3075.     /* LaunchProcess(STRPTR Name,VOID (*Entry)(VOID),BPTR Stream):
  3076.      *
  3077.      *    Launch a new process from given entry point, with given
  3078.      *    name and I/O stream.
  3079.      */
  3080.  
  3081. struct Process *
  3082. LaunchProcess(STRPTR Name,VOID (*Entry)(VOID),BPTR Stream)
  3083. {
  3084.     struct MsgPort *ConsoleTask;
  3085.  
  3086.     if(Stream && GoodStream(Stream))
  3087.         ConsoleTask = ((struct FileHandle *)BADDR(Stream))->fh_Type;
  3088.     else
  3089.         ConsoleTask = NULL;
  3090.  
  3091.     return(CreateNewProcTags(
  3092.         NP_Entry,        Entry,
  3093.         NP_StackSize,    8000,
  3094.         NP_Name,        Name,
  3095.         NP_Cli,            TRUE,
  3096.         NP_ConsoleTask,    ConsoleTask,
  3097.  
  3098.         ConsoleTask ? TAG_IGNORE : TAG_DONE,0,
  3099.  
  3100.         NP_Output,    ConsoleTask ? NULL : Stream,
  3101.  
  3102.         ConsoleTask ? NP_Input : TAG_IGNORE,Stream,
  3103.     TAG_DONE));
  3104. }
  3105.  
  3106.     /* String2Boolean(STRPTR String):
  3107.      *
  3108.      *    Compare string contents with table contents,
  3109.      *    map the string to a boolean value.
  3110.      */
  3111.  
  3112. BOOL
  3113. String2Boolean(STRPTR String)
  3114. {
  3115.     STATIC STRPTR TrueOptions[] =
  3116.     {
  3117.         "ON",
  3118.         "TRUE",
  3119.         "T",
  3120.         "YES",
  3121.         "Y",
  3122.         "1"
  3123.     };
  3124.  
  3125.     LONG i;
  3126.  
  3127.     for(i = 0 ; i < NUM_ELEMENTS(TrueOptions) ; i++)
  3128.     {
  3129.         if(!Stricmp(String,TrueOptions[i]))
  3130.             return(TRUE);
  3131.     }
  3132.  
  3133.     return(FALSE);
  3134. }
  3135.  
  3136.     /* SendMessageGetReply(struct MsgPort *Port,struct Message *Message):
  3137.      *
  3138.      *    Send a message to a given MsgPort and wait for
  3139.      *    the reply.
  3140.      */
  3141.  
  3142. VOID
  3143. SendMessageGetReply(struct MsgPort *Port,struct Message *Message)
  3144. {
  3145.     struct MsgPort LocalPort;
  3146.     struct MsgPort *ReplyPort;
  3147.  
  3148.     ReplyPort = Message->mn_ReplyPort;
  3149.  
  3150.     InitSinglePort(&LocalPort);
  3151.  
  3152.     Message->mn_ReplyPort = &LocalPort;
  3153.  
  3154.     SetSignal(0,SIGF_SINGLE);
  3155.  
  3156.     PutMsg(Port,Message);
  3157.     WaitPort(&LocalPort);
  3158.     GetMsg(&LocalPort);
  3159.  
  3160.     Message->mn_ReplyPort = ReplyPort;
  3161. }
  3162.  
  3163.     /* SetOnlineState(BOOL IsOnline):
  3164.      *
  3165.      *    Set the current online state.
  3166.      */
  3167.  
  3168. VOID
  3169. SetOnlineState(BOOL IsOnline,LONG BackTime)
  3170. {
  3171.     ObtainSemaphore(&OnlineSemaphore);
  3172.  
  3173.     WasOnline    = Online;
  3174.     Online        = IsOnline;
  3175.  
  3176.     if(!WasOnline && Online)
  3177.     {
  3178.         GetSysTime(&OnlineTime);
  3179.         OnlineTime.tv_secs -= BackTime;
  3180.     }
  3181.  
  3182.     if(WasOnline && !Online)
  3183.         ActivateJob(MainJobQueue,OnlineCleanupJob);
  3184.  
  3185.     ReleaseSemaphore(&OnlineSemaphore);
  3186. }
  3187.  
  3188.     /* SwapMem(APTR FromPtr,APTR ToPtr,LONG Size):
  3189.      *
  3190.      *    Exchange the contents of two memory regions.
  3191.      */
  3192.  
  3193. VOID
  3194. SwapMem(APTR FromPtr,APTR ToPtr,LONG Size)
  3195. {
  3196.     UBYTE *From,*To,c;
  3197.  
  3198.     From    = FromPtr;
  3199.     To        = ToPtr;
  3200.  
  3201.     while(Size--)
  3202.     {
  3203.         c        = *From;
  3204.         *From++    = *To;
  3205.         *To++    = c;
  3206.     }
  3207. }
  3208.  
  3209.     /* InitHook(struct Hook *Hook,HOOKFUNC Func,APTR Data):
  3210.      *
  3211.      *    Set up a callback hook function.
  3212.      */
  3213.  
  3214. VOID
  3215. InitHook(struct Hook *Hook,HOOKFUNC Func,APTR Data)
  3216. {
  3217.     #ifdef USE_GLUE
  3218.     {
  3219.         Hook->h_Entry        = HookEntry;
  3220.         Hook->h_SubEntry    = Func;
  3221.         Hook->h_Data        = Data;
  3222.     }
  3223.     #else
  3224.     {
  3225.         Hook->h_Entry        = Func;
  3226.         Hook->h_Data        = Data;
  3227.     }
  3228.     #endif    /* USE_GLUE */
  3229. }
  3230.  
  3231.     /* FitText(struct RastPort *RPort,UWORD Width,STRPTR String,LONG Len):
  3232.      *
  3233.      *    Check how many character fit into Width pixels.
  3234.      */
  3235.  
  3236. ULONG
  3237. FitText(struct RastPort *RPort,UWORD Width,STRPTR String,LONG Len)
  3238. {
  3239.     struct TextExtent Extent;
  3240.  
  3241.     if(Len == -1)
  3242.         Len = strlen(String);
  3243.  
  3244.     return(TextFit(RPort,String,Len,&Extent,NULL,1,Width,32767));
  3245. }
  3246.  
  3247.     /* DispatchRexxDialMsgList(BOOL Ok):
  3248.      *
  3249.      *    Dispatch all queued dial requests.
  3250.      */
  3251.  
  3252. VOID
  3253. DispatchRexxDialMsgList(BOOL Ok)
  3254. {
  3255.     struct RexxMsg *DialMsg;
  3256.     LONG Result;
  3257.  
  3258.     if(Ok)
  3259.         Result = RC_OK;
  3260.     else
  3261.         Result = RC_WARN;
  3262.  
  3263.     while(DialMsg = (struct RexxMsg *)RemHead(&RexxDialMsgList))
  3264.     {
  3265.         DialMsg->rm_Result1 = Result;
  3266.         DialMsg->rm_Result2 = 0;
  3267.  
  3268.         ReplyMsg((struct Message *)DialMsg);
  3269.     }
  3270. }
  3271.  
  3272.     /* CancelZModem():
  3273.      *
  3274.      *    Send the zmodem cancel sequence.
  3275.      */
  3276.  
  3277. VOID
  3278. CancelZModem()
  3279. {
  3280.     if(UsesZModem)
  3281.         DoSerialWrite(ZModemCancel,20);
  3282. }
  3283.  
  3284.     /* WaitForHandshake():
  3285.      *
  3286.      *    Clears the handshaking signal, then waits for it.
  3287.      *    Must be called while in Forbid().
  3288.      */
  3289.  
  3290. VOID
  3291. WaitForHandshake()
  3292. {
  3293.     SetSignal(0,SIG_HANDSHAKE);
  3294.     Wait(SIG_HANDSHAKE);
  3295. }
  3296.  
  3297.     /* ShakeHands(struct Task *Notify,ULONG NotifyMask):
  3298.      *
  3299.      *    Send a signal to a Task and wait for it to
  3300.      *    reply with the handshake signal.
  3301.      */
  3302.  
  3303. VOID
  3304. ShakeHands(struct Task *Notify,ULONG NotifyMask)
  3305. {
  3306.     if(Notify)
  3307.     {
  3308.         Forbid();
  3309.  
  3310.         Signal(Notify,NotifyMask);
  3311.  
  3312.         WaitForHandshake();
  3313.  
  3314.         Permit();
  3315.     }
  3316. }
  3317.  
  3318.     /* GetViewPortExtra(struct ViewPort *ViewPort):
  3319.      *
  3320.      *    Gets the extra information associated with a viewport.
  3321.      */
  3322.  
  3323. struct ViewPortExtra *
  3324. GetViewPortExtra(struct ViewPort *ViewPort)
  3325. {
  3326.     struct TagItem Tags[2] = { VTAG_VIEWPORTEXTRA_GET, NULL, TAG_DONE };
  3327.  
  3328.     if(!VideoControl(ViewPort->ColorMap,Tags))
  3329.         return((struct ViewPortExtra *)Tags[0].ti_Data);
  3330.     else
  3331.         return(NULL);
  3332. }
  3333.  
  3334.     /* OpenToAppend(STRPTR Name,BOOL *Created):
  3335.      *
  3336.      *    Open a plain AmigaDOS file to append data to it. If a new file
  3337.      *    is created this routine will indicate this by setting the
  3338.      *    boolean variable pointed to by "Created" to TRUE.
  3339.      */
  3340.  
  3341. BPTR
  3342. OpenToAppend(STRPTR Name,BOOL *Created)
  3343. {
  3344.     BPTR FileHandle;
  3345.     BPTR FileLock;
  3346.  
  3347.     if(FileLock = Lock(Name,EXCLUSIVE_LOCK))
  3348.     {
  3349.         if(!(FileHandle = OpenFromLock(FileLock)))
  3350.         {
  3351.             UnLock(FileLock);
  3352.  
  3353.             FileHandle = Open(Name,MODE_READWRITE);
  3354.         }
  3355.  
  3356.         if(FileHandle)
  3357.         {
  3358.             if(Seek(FileHandle,0,OFFSET_END) == -1)
  3359.             {
  3360.                 LONG Error;
  3361.  
  3362.                 Error = IoErr();
  3363.  
  3364.                 Close(FileHandle);
  3365.  
  3366.                 SetIoErr(Error);
  3367.  
  3368.                 return(NULL);
  3369.             }
  3370.         }
  3371.  
  3372.         if(Created)
  3373.             *Created = FALSE;
  3374.     }
  3375.     else
  3376.     {
  3377.         if(FileHandle = Open(Name,MODE_NEWFILE))
  3378.         {
  3379.             if(Created)
  3380.                 *Created = TRUE;
  3381.         }
  3382.     }
  3383.  
  3384.     return(FileHandle);
  3385. }
  3386.  
  3387.     /* PushStatus(WORD NewStatus):
  3388.      *
  3389.      *    Remember the current status and set the new one.
  3390.      */
  3391.  
  3392. VOID
  3393. PushStatus(WORD NewStatus)
  3394. {
  3395.     ObtainSemaphore(&StatusSemaphore);
  3396.  
  3397.     if(StatusStackPointer < 10)
  3398.         StatusStack[StatusStackPointer++] = NewStatus;
  3399.  
  3400.     ReleaseSemaphore(&StatusSemaphore);
  3401. }
  3402.  
  3403.     /* PopStatus():
  3404.      *
  3405.      *    Return to the old status value.
  3406.      */
  3407.  
  3408. VOID
  3409. PopStatus()
  3410. {
  3411.     ObtainSemaphore(&StatusSemaphore);
  3412.  
  3413.     if(StatusStackPointer > 0)
  3414.         StatusStackPointer--;
  3415.  
  3416.     ReleaseSemaphore(&StatusSemaphore);
  3417. }
  3418.  
  3419.     /* GetStatus():
  3420.      *
  3421.      *    Returns the current status.
  3422.      */
  3423.  
  3424. WORD
  3425. GetStatus()
  3426. {
  3427.     WORD Status;
  3428.  
  3429.     SafeObtainSemaphoreShared(&StatusSemaphore);
  3430.  
  3431.     if(StatusStackPointer > 0)
  3432.         Status = StatusStack[StatusStackPointer - 1];
  3433.     else
  3434.         Status = STATUS_READY;
  3435.  
  3436.     ReleaseSemaphore(&StatusSemaphore);
  3437.  
  3438.     if(Status == STATUS_READY && Get_xOFF())
  3439.         Status = STATUS_HOLDING;
  3440.  
  3441.     return(Status);
  3442. }
  3443.  
  3444.     /* Clear_xOFF():
  3445.      *
  3446.      *    Clears the xOFF stop marker.
  3447.      */
  3448.  
  3449. VOID
  3450. Clear_xOFF()
  3451. {
  3452.     ObtainSemaphore(&xONxOFF_Semaphore);
  3453.  
  3454.     xOFF_Enabled = FALSE;
  3455.  
  3456.     UpdateSerialJob();
  3457.  
  3458.     ReleaseSemaphore(&xONxOFF_Semaphore);
  3459. }
  3460.  
  3461.     /* Set_xOFF():
  3462.      *
  3463.      *    Sets the xOFF stop marker unless access to the
  3464.      *    marker is forbidden.
  3465.      */
  3466.  
  3467. VOID
  3468. Set_xOFF()
  3469. {
  3470.     ObtainSemaphore(&xONxOFF_Semaphore);
  3471.  
  3472.     if(xONxOFF_Lock == 0)
  3473.         xOFF_Enabled = TRUE;
  3474.  
  3475.     UpdateSerialJob();
  3476.  
  3477.     ReleaseSemaphore(&xONxOFF_Semaphore);
  3478. }
  3479.  
  3480.     /* Get_xOFF():
  3481.      *
  3482.      *    Queries the current state of the xOFF marker.
  3483.      */
  3484.  
  3485. BOOL
  3486. Get_xOFF()
  3487. {
  3488.     BOOL Result;
  3489.  
  3490.     SafeObtainSemaphoreShared(&xONxOFF_Semaphore);
  3491.  
  3492.     Result = xOFF_Enabled;
  3493.  
  3494.     ReleaseSemaphore(&xONxOFF_Semaphore);
  3495.  
  3496.     return(Result);
  3497. }
  3498.  
  3499.     /* Lock_xOFF():
  3500.      *
  3501.      *    Locks the current xOFF marker state.
  3502.      */
  3503.  
  3504. VOID
  3505. Lock_xOFF()
  3506. {
  3507.     ObtainSemaphore(&xONxOFF_Semaphore);
  3508.  
  3509.     xONxOFF_Lock++;
  3510.  
  3511.     ReleaseSemaphore(&xONxOFF_Semaphore);
  3512. }
  3513.  
  3514.     /* Unlock_xOFF():
  3515.      *
  3516.      *    Unlocks the current xOFF marker state.
  3517.      */
  3518.  
  3519. VOID
  3520. Unlock_xOFF()
  3521. {
  3522.     ObtainSemaphore(&xONxOFF_Semaphore);
  3523.  
  3524.     if(xONxOFF_Lock > 0)
  3525.         xONxOFF_Lock--;
  3526.  
  3527.     ReleaseSemaphore(&xONxOFF_Semaphore);
  3528. }
  3529.  
  3530.     /* MoveListViewNode():
  3531.      *
  3532.      *    Move the node of a list view somewhere.
  3533.      */
  3534.  
  3535. VOID
  3536. MoveListViewNode(LayoutHandle *Handle,struct List *List,LONG ListID,struct Node *Node,LONG *Offset,LONG How)
  3537. {
  3538.     LT_SetAttributes(Handle,ListID,
  3539.         GTLV_Labels,    ~0,
  3540.     TAG_DONE);
  3541.  
  3542.     MoveNode(List,Node,How);
  3543.  
  3544.     *Offset = GetNodeOffset(Node,List);
  3545.  
  3546.     LT_SetAttributes(Handle,ListID,
  3547.         GTLV_Labels,    List,
  3548.         LALV_Selected,    *Offset,
  3549.     TAG_DONE);
  3550. }
  3551.  
  3552.     /* StartProcessWaitForHandshake():
  3553.      *
  3554.      *    Create a new process and wait for the handshake
  3555.      *    signal.
  3556.      */
  3557.  
  3558. struct Process *
  3559. StartProcessWaitForHandshake(STRPTR Name,TASKENTRY Entry,...)
  3560. {
  3561.     struct Process *Process;
  3562.     va_list Args;
  3563.  
  3564.     va_start(Args,Entry);
  3565.  
  3566.     Forbid();
  3567.  
  3568.     if(Process = CreateNewProcTags(
  3569.         NP_Name,    Name,
  3570.         NP_Entry,    Entry,
  3571.     TAG_MORE,Args))
  3572.         WaitForHandshake();
  3573.  
  3574.     Permit();
  3575.  
  3576.     va_end(Args);
  3577.  
  3578.     return(Process);
  3579. }
  3580.  
  3581.     /* LocalGetCurrentDirName(STRPTR Buffer,LONG BufferSize):
  3582.      *
  3583.      *    Obtains the name of the "current" directory of the
  3584.      *    calling process, regardless of the current directory
  3585.      *    of the Shell environment the process may be running in.
  3586.      */
  3587.  
  3588. BOOL
  3589. LocalGetCurrentDirName(STRPTR Buffer,LONG BufferSize)
  3590. {
  3591.     return((BOOL)NameFromLock(((struct Process *)FindTask(NULL))->pr_CurrentDir,Buffer,BufferSize));
  3592. }
  3593.  
  3594.     /* SafeObtainSemaphoreShared():
  3595.      *
  3596.      *    This is for backwards compatibility with Kickstart 2.04 and
  3597.      *    avoids a deadlock when trying to get a shared lock on
  3598.      *    a semaphore already held in exclusive mode by the same Task.
  3599.      */
  3600.  
  3601. VOID
  3602. SafeObtainSemaphoreShared(struct SignalSemaphore *Semaphore)
  3603. {
  3604.         /* Do it right with Kickstart 3.x. */
  3605.  
  3606.     if(Kick30)
  3607.         ObtainSemaphoreShared(Semaphore);
  3608.     else
  3609.     {
  3610.             /* Try to get the shared semaphore */
  3611.  
  3612.         if(!AttemptSemaphoreShared(Semaphore))
  3613.         {
  3614.                 /* Check if we can get the exclusive version */
  3615.  
  3616.             if(!AttemptSemaphore(Semaphore))
  3617.             {
  3618.                     /* Oh well, wait for the shared lock */
  3619.  
  3620.                 ObtainSemaphoreShared(Semaphore);
  3621.             }
  3622.         }
  3623.     }
  3624. }
  3625.  
  3626.     /* LocalCreateTask(STRPTR Name,BYTE Priority,TASKENTRY Entry,ULONG StackSize,LONG NumArgs,...):
  3627.      *
  3628.      *    Special version of CreateTask() that allows for arguments to be passed to
  3629.      *    the Task to be created.
  3630.      */
  3631.  
  3632. struct Task *
  3633. LocalCreateTask(STRPTR Name,LONG Priority,TASKENTRY Entry,ULONG StackSize,LONG NumArgs,...)
  3634. {
  3635.         /* A MemList with an additional MemEntry following it. */
  3636.  
  3637.     struct FatMemList
  3638.     {
  3639.         struct MemList    MemList;
  3640.         struct MemEntry    MemEntry;
  3641.     };
  3642.  
  3643.     struct MemList *LocalMemList,*MemList;
  3644.     struct FatMemList FatMemList;
  3645.     struct Task *Task;
  3646.  
  3647.         /* Limit the Task priority to legal values. */
  3648.  
  3649.     if(Priority < -128)
  3650.         Priority = -128;
  3651.     else
  3652.     {
  3653.         if(Priority > 127)
  3654.             Priority = 127;
  3655.     }
  3656.  
  3657.         /* Clear the result. */
  3658.  
  3659.     Task = NULL;
  3660.  
  3661.         /* Round the stack size to a multiple of four. */
  3662.  
  3663.     StackSize = (StackSize + 3) & ~3;
  3664.  
  3665.         /* Reset the contents of the local memory allocation request. */
  3666.  
  3667.     memset(&FatMemList,0,sizeof(FatMemList));
  3668.     LocalMemList = &FatMemList.MemList;
  3669.  
  3670.         /* Set up the memory allocation request; we want room for
  3671.          * the Task structure and the requested stack size plus
  3672.          * any arguments to pass to the new Task.
  3673.          */
  3674.  
  3675.     LocalMemList->ml_NumEntries            = 2;
  3676.     LocalMemList->ml_ME[0].me_Reqs        = MEMF_ANY|MEMF_PUBLIC|MEMF_CLEAR;
  3677.     LocalMemList->ml_ME[0].me_Length    = sizeof(struct Task);
  3678.     LocalMemList->ml_ME[1].me_Reqs        = MEMF_ANY|MEMF_CLEAR;
  3679.     LocalMemList->ml_ME[1].me_Length    = StackSize + NumArgs * sizeof(LONG);
  3680.  
  3681.         /* Try the allocation. */
  3682.  
  3683.     if(MemList = AllocEntry(LocalMemList))
  3684.     {
  3685.             /* Check if the allocation did work. */
  3686.  
  3687.         if((ULONG)MemList & 0x80000000)
  3688.         {
  3689.                 /* Strip the failure bit. */
  3690.  
  3691.             MemList = (struct MemList *)((ULONG)MemList & ~0x80000000);
  3692.         }
  3693.         else
  3694.         {
  3695.                 /* So we got the memory for the Task. */
  3696.  
  3697.             Task = (struct Task *)MemList->ml_ME[0].me_Addr;
  3698.  
  3699.                 /* Initialize the Task data structure. We will not
  3700.                  * copy the name to a separate buffer, it is assumed
  3701.                  * that the name pointer will remain valid for the
  3702.                  * entire life time of this Task.
  3703.                  */
  3704.  
  3705.             Task->tc_Node.ln_Pri    = Priority;
  3706.             Task->tc_Node.ln_Type    = NT_TASK;
  3707.             Task->tc_Node.ln_Name    = Name;
  3708.  
  3709.             Task->tc_SPLower        = MemList->ml_ME[1].me_Addr;
  3710.             Task->tc_SPUpper        = (APTR)((ULONG)Task->tc_SPLower + MemList->ml_ME[1].me_Length);
  3711.             Task->tc_SPReg            = (APTR)((ULONG)Task->tc_SPUpper - NumArgs * sizeof(LONG));
  3712.  
  3713.                 /* Add the memory to be released when the Task exits. */
  3714.  
  3715.             NewList(&Task->tc_MemEntry);
  3716.             AddTail(&Task->tc_MemEntry,(struct Node *)MemList);
  3717.  
  3718.                 /* If there are any arguments to pass to the Task,
  3719.                  * copy them onto the stack.
  3720.                  */
  3721.  
  3722.             if(NumArgs > 0)
  3723.             {
  3724.                 va_list VarArgs;
  3725.  
  3726.                 va_start(VarArgs,NumArgs);
  3727.                 CopyMem(VarArgs,Task->tc_SPReg,NumArgs * sizeof(LONG));
  3728.                 va_end(VarArgs);
  3729.             }
  3730.  
  3731.                 /* Try to launch the Task... */
  3732.  
  3733.             Task = AddTask(Task,(APTR)Entry,NULL);
  3734.         }
  3735.  
  3736.             /* Check if the Task could be launched and clean
  3737.              * up if it couldn't.
  3738.              */
  3739.  
  3740.         if(Task == NULL && MemList != NULL)
  3741.             FreeEntry(MemList);
  3742.     }
  3743.  
  3744.     return(Task);
  3745. }
  3746.  
  3747.     /* ChangeWindowPtr(APTR *Old,APTR New):
  3748.      *
  3749.      *    Change the pr_WindowPtr entry and return the old value.
  3750.      */
  3751.  
  3752. VOID
  3753. ChangeWindowPtr(APTR *Old,APTR New)
  3754. {
  3755.     struct Process *CurrentProcess;
  3756.  
  3757.     CurrentProcess = (struct Process *)FindTask(NULL);
  3758.  
  3759.     *Old = CurrentProcess->pr_WindowPtr;
  3760.  
  3761.     CurrentProcess->pr_WindowPtr = New;
  3762. }
  3763.  
  3764.     /* RestoreWindowPtr(APTR Old):
  3765.      *
  3766.      *    Restore the pr_WindowPtr to whatever it was poiting to.
  3767.      */
  3768.  
  3769. VOID
  3770. RestoreWindowPtr(APTR Old)
  3771. {
  3772.     ((struct Process *)FindTask(NULL))->pr_WindowPtr = Old;
  3773. }
  3774.  
  3775.     /* DisableDOSRequesters(APTR *WindowPtr):
  3776.      *
  3777.      *    Turn off the AmigaDOS requesters.
  3778.      */
  3779.  
  3780. VOID
  3781. DisableDOSRequesters(APTR *WindowPtr)
  3782. {
  3783.     ChangeWindowPtr(WindowPtr,(APTR)-1);
  3784. }
  3785.  
  3786.     /* EnableDOSRequesters(APTR WindowPtr):
  3787.      *
  3788.      *    Turn the AmigaDOS requesters back on.
  3789.      */
  3790.  
  3791. VOID
  3792. EnableDOSRequesters(APTR WindowPtr)
  3793. {
  3794.     RestoreWindowPtr(WindowPtr);
  3795. }
  3796.  
  3797.     /* SpeechSynthesizerAvailable():
  3798.      *
  3799.      *    Checks if the speech synthesizer is available for use.
  3800.      */
  3801.  
  3802. BOOL
  3803. SpeechSynthesizerAvailable()
  3804. {
  3805.     struct Library *LocalTranslatorBase;
  3806.     BOOL SpeechAvailable;
  3807.  
  3808.     SpeechAvailable = FALSE;
  3809.  
  3810.     if(LocalTranslatorBase = OpenLibrary("translator.library",0))
  3811.     {
  3812.         struct narrator_rb NarratorRequest;
  3813.  
  3814.         memset(&NarratorRequest,0,sizeof(NarratorRequest));
  3815.         NarratorRequest.message.io_Message.mn_Length = sizeof(NarratorRequest);
  3816.  
  3817.         if(!OpenDevice("narrator.device",0,(struct IORequest *)&NarratorRequest,NULL))
  3818.         {
  3819.             SpeechAvailable = TRUE;
  3820.  
  3821.             CloseDevice((struct IORequest *)&NarratorRequest);
  3822.         }
  3823.  
  3824.         CloseLibrary(LocalTranslatorBase);
  3825.     }
  3826.  
  3827.     return(SpeechAvailable);
  3828. }
  3829.  
  3830.     /* CurrentTimeToStamp(struct DateStamp *Stamp):
  3831.      *
  3832.      *    A replacement for DateStamp().
  3833.      */
  3834.  
  3835. VOID
  3836. CurrentTimeToStamp(struct DateStamp *Stamp)
  3837. {
  3838.     struct timeval Now;
  3839.  
  3840.     GetSysTime(&Now);
  3841.  
  3842.     Stamp->ds_Days        = Now.tv_secs / (24 * 60 * 60);
  3843.     Stamp->ds_Minute    = (Now.tv_secs % (24 * 60 * 60)) / 60;
  3844.     Stamp->ds_Tick        = (Now.tv_secs % 60) * TICKS_PER_SECOND + (TICKS_PER_SECOND * Now.tv_micro) / MILLION;
  3845. }
  3846.  
  3847.     /* SmartOpenDiskFont(struct TextAttr *TextAttr):
  3848.      *
  3849.      *    Opens a disk-resident font. Does not require diskfont.library
  3850.      *    to be open all the time while the program is running.
  3851.      */
  3852.  
  3853. struct TextFont *
  3854. SmartOpenDiskFont(struct TextAttr *TextAttr)
  3855. {
  3856.     struct TextFont *Result;
  3857.  
  3858.     Result = NULL;
  3859.  
  3860.     if(DiskfontBase = OpenLibrary("diskfont.library",0))
  3861.     {
  3862.         Result = OpenDiskFont(TextAttr);
  3863.  
  3864.         CloseLibrary(DiskfontBase);
  3865.     }
  3866.  
  3867.     if(!Result)
  3868.         Result = OpenFont(TextAttr);
  3869.  
  3870.     return(Result);
  3871. }
  3872.  
  3873.     /* ArmLimit(ULONG MinutesToGo):
  3874.      *
  3875.      *    Arm the limit counter. We remember the time when the limit
  3876.      *    will be exceeded.
  3877.      */
  3878.  
  3879. VOID
  3880. ArmLimit(ULONG MinutesToGo)
  3881. {
  3882.     GetSysTime(&LimitTime);
  3883.     LimitTime.tv_secs += MinutesToGo * 60;
  3884. }
  3885.  
  3886.     /* DisarmLimit():
  3887.      *
  3888.      *    Clear the limit counter.
  3889.      */
  3890.  
  3891. VOID
  3892. DisarmLimit()
  3893. {
  3894.     memset(&LimitTime,0,sizeof(LimitTime));
  3895. }
  3896.  
  3897.     /* CheckLimit():
  3898.      *
  3899.      *    Check if the limit counter has been triggered.
  3900.      *    If triggered, clear the limit counter.
  3901.      */
  3902.  
  3903. BOOL
  3904. CheckLimit()
  3905. {
  3906.     BOOL Triggered;
  3907.  
  3908.     Triggered = FALSE;
  3909.  
  3910.     if(LimitTime.tv_secs > 0 || LimitTime.tv_micro > 0)
  3911.     {
  3912.         struct timeval Now;
  3913.  
  3914.         GetSysTime(&Now);
  3915.  
  3916.         if(-CmpTime(&Now,&LimitTime) >= 0)
  3917.             Triggered = TRUE;
  3918.     }
  3919.  
  3920.     if(Triggered)
  3921.         DisarmLimit();
  3922.  
  3923.     return(Triggered);
  3924. }
  3925.  
  3926.     /* GetStackSize():
  3927.      *
  3928.      *    Return the total stack size available for this program.
  3929.      */
  3930.  
  3931. ULONG
  3932. GetStackSize(VOID)
  3933. {
  3934.     struct Process * pr = (struct Process *)FindTask(NULL);
  3935.     ULONG result;
  3936.  
  3937.     if(pr->pr_CLI != NULL)
  3938.     {
  3939.         result = *(ULONG *)pr->pr_ReturnAddr;
  3940.     }
  3941.     else
  3942.     {
  3943.         result = (ULONG)pr->pr_Task.tc_SPUpper - (ULONG)pr->pr_Task.tc_SPLower;
  3944.     }
  3945.  
  3946.     return(result);
  3947. }
  3948.